LCOV - code coverage report
Current view: top level - src - qs_linres_methods.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:42dac4a) Lines: 96.3 % 407 392
Test Date: 2025-07-25 12:55:17 Functions: 100.0 % 9 9

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2025 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              : !> \par History
     212              : !>      07.2005 created [MI]
     213              : !> \author MI
     214              : ! **************************************************************************************************
     215         5044 :    SUBROUTINE linres_solver(p_env, qs_env, psi1, h1_psi0, psi0_order, iounit, should_stop)
     216              :       TYPE(qs_p_env_type)                                :: p_env
     217              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     218              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: psi1, h1_psi0, psi0_order
     219              :       INTEGER, INTENT(IN)                                :: iounit
     220              :       LOGICAL, INTENT(OUT)                               :: should_stop
     221              : 
     222              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'linres_solver'
     223              : 
     224              :       INTEGER                                            :: handle, ispin, iter, maxnmo, nao, ncol, &
     225              :                                                             nmo, nocc, nspins
     226              :       LOGICAL                                            :: restart
     227              :       REAL(dp)                                           :: alpha, beta, norm_res, t1, t2
     228         5044 :       REAL(dp), DIMENSION(:), POINTER                    :: tr_pAp, tr_rz0, tr_rz00, tr_rz1
     229              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     230              :       TYPE(cp_fm_type)                                   :: buf
     231         5044 :       TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:)        :: Ap, chc, mo_coeff_array, p, r, z
     232         5044 :       TYPE(cp_fm_type), DIMENSION(:), POINTER            :: Sc
     233              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     234         5044 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s, matrix_t
     235              :       TYPE(dbcsr_type), POINTER                          :: matrix_x
     236              :       TYPE(dft_control_type), POINTER                    :: dft_control
     237              :       TYPE(linres_control_type), POINTER                 :: linres_control
     238         5044 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     239              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     240              : 
     241         5044 :       CALL timeset(routineN, handle)
     242              : 
     243         5044 :       NULLIFY (dft_control, linres_control, matrix_s, matrix_t, matrix_ks, para_env)
     244         5044 :       NULLIFY (mos, tmp_fm_struct, mo_coeff)
     245              : 
     246         5044 :       t1 = m_walltime()
     247              : 
     248              :       CALL get_qs_env(qs_env=qs_env, &
     249              :                       matrix_ks=matrix_ks, &
     250              :                       matrix_s=matrix_s, &
     251              :                       kinetic=matrix_t, &
     252              :                       dft_control=dft_control, &
     253              :                       linres_control=linres_control, &
     254              :                       para_env=para_env, &
     255         5044 :                       mos=mos)
     256              : 
     257         5044 :       nspins = dft_control%nspins
     258         5044 :       CALL cp_fm_get_info(psi1(1), nrow_global=nao)
     259         5044 :       maxnmo = 0
     260        12140 :       DO ispin = 1, nspins
     261         7096 :          CALL cp_fm_get_info(psi1(ispin), ncol_global=ncol)
     262        12140 :          maxnmo = MAX(maxnmo, ncol)
     263              :       END DO
     264              :       !
     265         5044 :       CALL check_p_env_init(p_env, linres_control, nspins)
     266              :       !
     267              :       ! allocate the vectors
     268              :       ALLOCATE (tr_pAp(nspins), tr_rz0(nspins), tr_rz00(nspins), tr_rz1(nspins), &
     269        83868 :                 r(nspins), p(nspins), z(nspins), Ap(nspins))
     270              :       !
     271        12140 :       DO ispin = 1, nspins
     272         7096 :          CALL cp_fm_create(r(ispin), psi1(ispin)%matrix_struct)
     273         7096 :          CALL cp_fm_create(p(ispin), psi1(ispin)%matrix_struct)
     274         7096 :          CALL cp_fm_create(z(ispin), psi1(ispin)%matrix_struct)
     275        12140 :          CALL cp_fm_create(Ap(ispin), psi1(ispin)%matrix_struct)
     276              :       END DO
     277              :       !
     278              :       ! build C0 occupied vectors and S*C0 matrix
     279        34368 :       ALLOCATE (Sc(nspins), mo_coeff_array(nspins))
     280        12140 :       DO ispin = 1, nspins
     281         7096 :          CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff, homo=nocc)
     282         7096 :          NULLIFY (tmp_fm_struct)
     283              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nao, &
     284              :                                   ncol_global=nocc, para_env=para_env, &
     285         7096 :                                   context=mo_coeff%matrix_struct%context)
     286         7096 :          CALL cp_fm_create(mo_coeff_array(ispin), tmp_fm_struct)
     287         7096 :          CALL cp_fm_to_fm(mo_coeff, mo_coeff_array(ispin), nocc)
     288         7096 :          CALL cp_fm_create(Sc(ispin), tmp_fm_struct)
     289        19236 :          CALL cp_fm_struct_release(tmp_fm_struct)
     290              :       END DO
     291              :       !
     292              :       ! Allocate C0_order'*H*C0_order
     293        22228 :       ALLOCATE (chc(nspins))
     294        12140 :       DO ispin = 1, nspins
     295         7096 :          CALL cp_fm_get_info(psi1(ispin), ncol_global=nmo)
     296         7096 :          NULLIFY (tmp_fm_struct)
     297              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nmo, &
     298              :                                   ncol_global=nmo, para_env=para_env, &
     299         7096 :                                   context=mo_coeff%matrix_struct%context)
     300         7096 :          CALL cp_fm_create(chc(ispin), tmp_fm_struct)
     301        19236 :          CALL cp_fm_struct_release(tmp_fm_struct)
     302              :       END DO
     303              :       !
     304        12140 :       DO ispin = 1, nspins
     305              :          !
     306              :          ! C0_order' * H * C0_order
     307              :          ASSOCIATE (mo_coeff => psi0_order(ispin))
     308         7096 :             CALL cp_fm_create(buf, mo_coeff%matrix_struct)
     309         7096 :             CALL cp_fm_get_info(mo_coeff, ncol_global=ncol)
     310         7096 :             CALL cp_dbcsr_sm_fm_multiply(matrix_ks(ispin)%matrix, mo_coeff, buf, ncol)
     311         7096 :             CALL parallel_gemm('T', 'N', ncol, ncol, nao, -1.0_dp, mo_coeff, buf, 0.0_dp, chc(ispin))
     312         7096 :             CALL cp_fm_release(buf)
     313              :          END ASSOCIATE
     314              :          !
     315              :          ! S * C0
     316         7096 :          CALL cp_fm_get_info(mo_coeff_array(ispin), ncol_global=ncol)
     317        19236 :          CALL cp_dbcsr_sm_fm_multiply(matrix_s(1)%matrix, mo_coeff_array(ispin), Sc(ispin), ncol)
     318              :       END DO
     319              :       !
     320              :       ! header
     321         5044 :       IF (iounit > 0) THEN
     322              :          WRITE (iounit, "(/,T3,A,T16,A,T25,A,T38,A,T52,A,T72,A,/,T3,A)") &
     323         2514 :             "Iteration", "Method", "Restart", "Stepsize", "Convergence", "Time", &
     324         5028 :             REPEAT("-", 78)
     325              :       END IF
     326              :       !
     327              :       ! orthogonalize x with respect to the psi0
     328         5044 :       CALL preortho(psi1, mo_coeff_array, Sc)
     329              :       !
     330              :       ! build the preconditioner
     331         5044 :       IF (linres_control%preconditioner_type /= ot_precond_none) THEN
     332         5044 :          IF (p_env%new_preconditioner) THEN
     333         2672 :             DO ispin = 1, nspins
     334         2672 :                IF (ASSOCIATED(matrix_t)) THEN
     335              :                   CALL make_preconditioner(p_env%preconditioner(ispin), &
     336              :                                            linres_control%preconditioner_type, ot_precond_solver_default, &
     337              :                                            matrix_ks(ispin)%matrix, matrix_s(1)%matrix, matrix_t(1)%matrix, &
     338         1410 :                                            mos(ispin), linres_control%energy_gap)
     339              :                ELSE
     340           24 :                   NULLIFY (matrix_x)
     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_x, &
     344           24 :                                            mos(ispin), linres_control%energy_gap)
     345              :                END IF
     346              :             END DO
     347         1238 :             p_env%new_preconditioner = .FALSE.
     348              :          END IF
     349              :       END IF
     350              :       !
     351              :       ! initialization of the linear solver
     352              :       !
     353              :       ! A * x0
     354         5044 :       CALL apply_op(qs_env, p_env, psi0_order, psi1, Ap, chc)
     355              :       !
     356              :       !
     357              :       ! r_0 = b - Ax0
     358        12140 :       DO ispin = 1, nspins
     359         7096 :          CALL cp_fm_to_fm(h1_psi0(ispin), r(ispin))
     360        12140 :          CALL cp_fm_scale_and_add(-1.0_dp, r(ispin), -1.0_dp, Ap(ispin))
     361              :       END DO
     362              :       !
     363              :       ! proj r
     364         5044 :       CALL postortho(r, mo_coeff_array, Sc)
     365              :       !
     366              :       ! preconditioner
     367         5044 :       linres_control%flag = ""
     368         5044 :       IF (linres_control%preconditioner_type .EQ. ot_precond_none) THEN
     369              :          !
     370              :          ! z_0 = r_0
     371            0 :          DO ispin = 1, nspins
     372            0 :             CALL cp_fm_to_fm(r(ispin), z(ispin))
     373              :          END DO
     374            0 :          linres_control%flag = "CG"
     375              :       ELSE
     376              :          !
     377              :          ! z_0 = M * r_0
     378        12140 :          DO ispin = 1, nspins
     379              :             CALL apply_preconditioner(p_env%preconditioner(ispin), r(ispin), &
     380        12140 :                                       z(ispin))
     381              :          END DO
     382         5044 :          linres_control%flag = "PCG"
     383              :       END IF
     384              :       !
     385        12140 :       DO ispin = 1, nspins
     386              :          !
     387              :          ! p_0 = z_0
     388         7096 :          CALL cp_fm_to_fm(z(ispin), p(ispin))
     389              :          !
     390              :          ! trace(r_0 * z_0)
     391        12140 :          CALL cp_fm_trace(r(ispin), z(ispin), tr_rz0(ispin))
     392              :       END DO
     393        12140 :       IF (SUM(tr_rz0) < 0.0_dp) CPABORT("tr(r_j*z_j) < 0")
     394        12140 :       norm_res = ABS(SUM(tr_rz0))/SQRT(REAL(nspins*nao*maxnmo, dp))
     395              :       !
     396         5044 :       alpha = 0.0_dp
     397         5044 :       restart = .FALSE.
     398         5044 :       should_stop = .FALSE.
     399        33114 :       iteration: DO iter = 1, linres_control%max_iter
     400              :          !
     401              :          ! check convergence
     402        31810 :          linres_control%converged = .FALSE.
     403        31810 :          IF (norm_res .LT. linres_control%eps) THEN
     404         3740 :             linres_control%converged = .TRUE.
     405              :          END IF
     406              :          !
     407        31810 :          t2 = m_walltime()
     408              :          IF (iter .EQ. 1 .OR. MOD(iter, 1) .EQ. 0 .OR. linres_control%converged &
     409              :              .OR. restart .OR. should_stop) THEN
     410        31810 :             IF (iounit > 0) THEN
     411              :                WRITE (iounit, "(T5,I5,T18,A3,T28,L1,T38,1E8.2,T48,F16.10,T68,F8.2)") &
     412        15839 :                   iter, linres_control%flag, restart, alpha, norm_res, t2 - t1
     413        15839 :                CALL m_flush(iounit)
     414              :             END IF
     415              :          END IF
     416              :          !
     417        31810 :          IF (linres_control%converged) THEN
     418         3740 :             IF (iounit > 0) THEN
     419         1862 :                WRITE (iounit, "(T3,A,I4,A)") "The linear solver converged in ", iter, " iterations."
     420         1862 :                CALL m_flush(iounit)
     421              :             END IF
     422              :             EXIT iteration
     423        28070 :          ELSE IF (should_stop) THEN
     424            0 :             IF (iounit > 0) THEN
     425            0 :                WRITE (iounit, "(T3,A,I4,A)") "The linear solver did NOT converge! External stop"
     426            0 :                CALL m_flush(iounit)
     427              :             END IF
     428              :             EXIT iteration
     429              :          END IF
     430              :          !
     431              :          ! Max number of iteration reached
     432        28070 :          IF (iter == linres_control%max_iter) THEN
     433         1304 :             IF (iounit > 0) THEN
     434              :                CALL cp_warn(__LOCATION__, &
     435          652 :                             "The linear solver didn't converge! Maximum number of iterations reached.")
     436          652 :                CALL m_flush(iounit)
     437              :             END IF
     438         1304 :             linres_control%converged = .FALSE.
     439              :          END IF
     440              :          !
     441              :          ! Apply the operators that do not depend on the perturbation
     442        28070 :          CALL apply_op(qs_env, p_env, psi0_order, p, Ap, chc)
     443              :          !
     444              :          ! proj Ap onto the virtual subspace
     445        28070 :          CALL postortho(Ap, mo_coeff_array, Sc)
     446              :          !
     447        68780 :          DO ispin = 1, nspins
     448              :             !
     449              :             ! tr(Ap_j*p_j)
     450        68780 :             CALL cp_fm_trace(Ap(ispin), p(ispin), tr_pAp(ispin))
     451              :          END DO
     452              :          !
     453              :          ! alpha = tr(r_j*z_j) / tr(Ap_j*p_j)
     454        68780 :          IF (SUM(tr_pAp) < 1.0e-10_dp) THEN
     455          172 :             alpha = 1.0_dp
     456              :          ELSE
     457       108974 :             alpha = SUM(tr_rz0)/SUM(tr_pAp)
     458              :          END IF
     459        68780 :          DO ispin = 1, nspins
     460              :             !
     461              :             ! x_j+1 = x_j + alpha * p_j
     462        68780 :             CALL cp_fm_scale_and_add(1.0_dp, psi1(ispin), alpha, p(ispin))
     463              :          END DO
     464              :          !
     465              :          ! need to recompute the residue
     466        28070 :          restart = .FALSE.
     467        28070 :          IF (MOD(iter, linres_control%restart_every) .EQ. 0) THEN
     468              :             !
     469              :             ! r_j+1 = b - A * x_j+1
     470          206 :             CALL apply_op(qs_env, p_env, psi0_order, psi1, Ap, chc)
     471              :             !
     472          446 :             DO ispin = 1, nspins
     473          240 :                CALL cp_fm_to_fm(h1_psi0(ispin), r(ispin))
     474          446 :                CALL cp_fm_scale_and_add(-1.0_dp, r(ispin), -1.0_dp, Ap(ispin))
     475              :             END DO
     476          206 :             CALL postortho(r, mo_coeff_array, Sc)
     477              :             !
     478          206 :             restart = .TRUE.
     479              :          ELSE
     480              :             ! proj Ap onto the virtual subspace
     481        27864 :             CALL postortho(Ap, mo_coeff_array, Sc)
     482              :             !
     483              :             ! r_j+1 = r_j - alpha * Ap_j
     484        68334 :             DO ispin = 1, nspins
     485        68334 :                CALL cp_fm_scale_and_add(1.0_dp, r(ispin), -alpha, Ap(ispin))
     486              :             END DO
     487        27864 :             restart = .FALSE.
     488              :          END IF
     489              :          !
     490              :          ! preconditioner
     491        28070 :          linres_control%flag = ""
     492        28070 :          IF (linres_control%preconditioner_type .EQ. ot_precond_none) THEN
     493              :             !
     494              :             ! z_j+1 = r_j+1
     495            0 :             DO ispin = 1, nspins
     496            0 :                CALL cp_fm_to_fm(r(ispin), z(ispin))
     497              :             END DO
     498            0 :             linres_control%flag = "CG"
     499              :          ELSE
     500              :             !
     501              :             ! z_j+1 = M * r_j+1
     502        68780 :             DO ispin = 1, nspins
     503              :                CALL apply_preconditioner(p_env%preconditioner(ispin), r(ispin), &
     504        68780 :                                          z(ispin))
     505              :             END DO
     506        28070 :             linres_control%flag = "PCG"
     507              :          END IF
     508              :          !
     509        68780 :          DO ispin = 1, nspins
     510              :             !
     511              :             ! tr(r_j+1*z_j+1)
     512        68780 :             CALL cp_fm_trace(r(ispin), z(ispin), tr_rz1(ispin))
     513              :          END DO
     514        68780 :          IF (SUM(tr_rz1) < 0.0_dp) CPABORT("tr(r_j+1*z_j+1) < 0")
     515        68780 :          norm_res = SUM(tr_rz1)/SQRT(REAL(nspins*nao*maxnmo, dp))
     516              :          !
     517              :          ! beta = tr(r_j+1*z_j+1) / tr(r_j*z_j)
     518        68780 :          IF (SUM(tr_rz0) < 1.0e-10_dp) THEN
     519          210 :             beta = 0.0_dp
     520              :          ELSE
     521       108860 :             beta = SUM(tr_rz1)/SUM(tr_rz0)
     522              :          END IF
     523        68780 :          DO ispin = 1, nspins
     524              :             !
     525              :             ! p_j+1 = z_j+1 + beta * p_j
     526        40710 :             CALL cp_fm_scale_and_add(beta, p(ispin), 1.0_dp, z(ispin))
     527        40710 :             tr_rz00(ispin) = tr_rz0(ispin)
     528        68780 :             tr_rz0(ispin) = tr_rz1(ispin)
     529              :          END DO
     530              :          !
     531              :          ! Can we exit the SCF loop?
     532              :          CALL external_control(should_stop, "LINRES", target_time=qs_env%target_time, &
     533        29374 :                                start_time=qs_env%start_time)
     534              : 
     535              :       END DO iteration
     536              :       !
     537              :       ! proj psi1
     538         5044 :       CALL preortho(psi1, mo_coeff_array, Sc)
     539              :       !
     540              :       !
     541              :       ! clean up
     542         5044 :       CALL cp_fm_release(r)
     543         5044 :       CALL cp_fm_release(p)
     544         5044 :       CALL cp_fm_release(z)
     545         5044 :       CALL cp_fm_release(Ap)
     546              :       !
     547         5044 :       CALL cp_fm_release(mo_coeff_array)
     548         5044 :       CALL cp_fm_release(Sc)
     549         5044 :       CALL cp_fm_release(chc)
     550              :       !
     551         5044 :       DEALLOCATE (tr_pAp, tr_rz0, tr_rz00, tr_rz1)
     552              :       !
     553         5044 :       CALL timestop(handle)
     554              :       !
     555        15132 :    END SUBROUTINE linres_solver
     556              : 
     557              : ! **************************************************************************************************
     558              : !> \brief ...
     559              : !> \param qs_env ...
     560              : !> \param p_env ...
     561              : !> \param c0 ...
     562              : !> \param v ...
     563              : !> \param Av ...
     564              : !> \param chc ...
     565              : ! **************************************************************************************************
     566        33320 :    SUBROUTINE apply_op(qs_env, p_env, c0, v, Av, chc)
     567              :       !
     568              :       TYPE(qs_environment_type), INTENT(IN), POINTER     :: qs_env
     569              :       TYPE(qs_p_env_type)                                :: p_env
     570              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: c0, v
     571              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(INOUT)      :: Av
     572              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: chc
     573              : 
     574              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'apply_op'
     575              : 
     576              :       INTEGER                                            :: handle, ispin, nc1, nc2, nc3, nc4, nr1, &
     577              :                                                             nr2, nr3, nr4, nspins
     578              :       REAL(dp)                                           :: chksum
     579        33320 :       TYPE(dbcsr_p_type), DIMENSION(:), POINTER          :: matrix_ks, matrix_s
     580              :       TYPE(dft_control_type), POINTER                    :: dft_control
     581              :       TYPE(linres_control_type), POINTER                 :: linres_control
     582              :       TYPE(qs_rho_type), POINTER                         :: rho
     583              : 
     584        33320 :       CALL timeset(routineN, handle)
     585              : 
     586        33320 :       NULLIFY (dft_control, matrix_ks, matrix_s, linres_control)
     587              :       CALL get_qs_env(qs_env=qs_env, &
     588              :                       matrix_ks=matrix_ks, &
     589              :                       matrix_s=matrix_s, &
     590              :                       dft_control=dft_control, &
     591        33320 :                       linres_control=linres_control)
     592              : 
     593        33320 :       nspins = dft_control%nspins
     594              : 
     595        81366 :       DO ispin = 1, nspins
     596              :          !c0, v, Av, chc
     597        48046 :          CALL cp_fm_get_info(c0(ispin), ncol_global=nc1, nrow_global=nr1)
     598        48046 :          CALL cp_fm_get_info(v(ispin), ncol_global=nc2, nrow_global=nr2)
     599        48046 :          CALL cp_fm_get_info(Av(ispin), ncol_global=nc3, nrow_global=nr3)
     600        48046 :          CALL cp_fm_get_info(chc(ispin), ncol_global=nc4, nrow_global=nr4)
     601        48046 :          IF (.NOT. (nc1 == nc2 .AND. nr1 == nr2 .AND. nc1 == nc3 .AND. nr1 == nr3 &
     602        81366 :                     .AND. nc4 == nr4 .AND. nc1 <= nc4)) THEN
     603              :             CALL cp_abort(__LOCATION__, &
     604            0 :                           "Number of vectors inconsistent or CHC matrix too small")
     605              :          END IF
     606              :       END DO
     607              : 
     608              :       ! apply the uncoupled operator
     609        81366 :       DO ispin = 1, nspins
     610              :          CALL apply_op_1(v(ispin), Av(ispin), matrix_ks(ispin)%matrix, &
     611        81366 :                          matrix_s(1)%matrix, chc(ispin))
     612              :       END DO
     613              : 
     614        33320 :       IF (linres_control%do_kernel) THEN
     615              : 
     616              :          ! build DM, refill p1, build_dm_response keeps sparse structure
     617        19330 :          DO ispin = 1, nspins
     618        19330 :             CALL dbcsr_copy(p_env%p1(ispin)%matrix, matrix_s(1)%matrix)
     619              :          END DO
     620         9162 :          CALL build_dm_response(c0, v, p_env%p1)
     621              : 
     622         9162 :          chksum = 0.0_dp
     623        19330 :          DO ispin = 1, nspins
     624        19330 :             chksum = chksum + dbcsr_checksum(p_env%p1(ispin)%matrix)
     625              :          END DO
     626              : 
     627              :          ! skip the kernel if the DM is very small
     628         9162 :          IF (chksum .GT. 1.0E-14_dp) THEN
     629              : 
     630         7730 :             CALL p_env_check_i_alloc(p_env, qs_env)
     631              : 
     632         7730 :             CALL p_env_update_rho(p_env, qs_env)
     633              : 
     634         7730 :             CALL get_qs_env(qs_env, rho=rho) ! that could be called before
     635         7730 :             CALL qs_rho_update_rho(rho, qs_env=qs_env) ! that could be called before
     636         7730 :             IF (dft_control%qs_control%gapw) THEN
     637          792 :                CALL prepare_gapw_den(qs_env)
     638         6938 :             ELSEIF (dft_control%qs_control%gapw_xc) THEN
     639          352 :                CALL prepare_gapw_den(qs_env, do_rho0=.FALSE.)
     640              :             END IF
     641              : 
     642        16316 :             DO ispin = 1, nspins
     643         8586 :                CALL dbcsr_set(p_env%kpp1(ispin)%matrix, 0.0_dp)
     644        16316 :                IF (ASSOCIATED(p_env%kpp1_admm)) CALL dbcsr_set(p_env%kpp1_admm(ispin)%matrix, 0.0_dp)
     645              :             END DO
     646              : 
     647         7730 :             CALL apply_op_2(qs_env, p_env, c0, Av)
     648              : 
     649              :          END IF
     650              : 
     651              :       END IF
     652              : 
     653        33320 :       CALL timestop(handle)
     654              : 
     655        33320 :    END SUBROUTINE apply_op
     656              : 
     657              : ! **************************************************************************************************
     658              : !> \brief ...
     659              : !> \param v ...
     660              : !> \param Av ...
     661              : !> \param matrix_ks ...
     662              : !> \param matrix_s ...
     663              : !> \param chc ...
     664              : ! **************************************************************************************************
     665       144138 :    SUBROUTINE apply_op_1(v, Av, matrix_ks, matrix_s, chc)
     666              :       !
     667              :       TYPE(cp_fm_type), INTENT(IN)                       :: v
     668              :       TYPE(cp_fm_type), INTENT(INOUT)                    :: Av
     669              :       TYPE(dbcsr_type), INTENT(IN)                       :: matrix_ks, matrix_s
     670              :       TYPE(cp_fm_type), INTENT(IN)                       :: chc
     671              : 
     672              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'apply_op_1'
     673              : 
     674              :       INTEGER                                            :: handle, ncol, nrow
     675              :       TYPE(cp_fm_type)                                   :: buf
     676              : 
     677        48046 :       CALL timeset(routineN, handle)
     678              :       !
     679        48046 :       CALL cp_fm_create(buf, v%matrix_struct)
     680              :       !
     681        48046 :       CALL cp_fm_get_info(v, ncol_global=ncol, nrow_global=nrow)
     682              :       ! H * v
     683        48046 :       CALL cp_dbcsr_sm_fm_multiply(matrix_ks, v, Av, ncol)
     684              :       ! v * e  (chc already multiplied by -1)
     685        48046 :       CALL parallel_gemm('N', 'N', nrow, ncol, ncol, 1.0_dp, v, chc, 0.0_dp, buf)
     686              :       ! S * ve
     687        48046 :       CALL cp_dbcsr_sm_fm_multiply(matrix_s, buf, Av, ncol, alpha=1.0_dp, beta=1.0_dp)
     688              :       !Results is H*C1 - S*<iHj>*C1
     689              :       !
     690        48046 :       CALL cp_fm_release(buf)
     691              :       !
     692        48046 :       CALL timestop(handle)
     693              :       !
     694        48046 :    END SUBROUTINE apply_op_1
     695              : 
     696              : !MERGE
     697              : ! **************************************************************************************************
     698              : !> \brief ...
     699              : !> \param v ...
     700              : !> \param psi0 ...
     701              : !> \param S_psi0 ...
     702              : ! **************************************************************************************************
     703        10088 :    SUBROUTINE preortho(v, psi0, S_psi0)
     704              :       !v = (I-PS)v
     705              :       !
     706              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: v, psi0, S_psi0
     707              : 
     708              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'preortho'
     709              : 
     710              :       INTEGER                                            :: handle, ispin, mp, mt, mv, np, nspins, &
     711              :                                                             nt, nv
     712              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     713              :       TYPE(cp_fm_type)                                   :: buf
     714              : 
     715        10088 :       CALL timeset(routineN, handle)
     716              :       !
     717        10088 :       NULLIFY (tmp_fm_struct)
     718              :       !
     719        10088 :       nspins = SIZE(v, 1)
     720              :       !
     721        24280 :       DO ispin = 1, nspins
     722        14192 :          CALL cp_fm_get_info(v(ispin), ncol_global=mv, nrow_global=nv)
     723        14192 :          CALL cp_fm_get_info(psi0(ispin), ncol_global=mp, nrow_global=np)
     724              :          !
     725              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nv, ncol_global=mp, &
     726              :                                   para_env=v(ispin)%matrix_struct%para_env, &
     727        14192 :                                   context=v(ispin)%matrix_struct%context)
     728        14192 :          CALL cp_fm_create(buf, tmp_fm_struct)
     729        14192 :          CALL cp_fm_struct_release(tmp_fm_struct)
     730              :          !
     731        14192 :          CALL cp_fm_get_info(buf, ncol_global=mt, nrow_global=nt)
     732        14192 :          CPASSERT(nv == np)
     733        14192 :          CPASSERT(mt >= mv)
     734        14192 :          CPASSERT(mt >= mp)
     735        14192 :          CPASSERT(nt == nv)
     736              :          !
     737              :          ! buf = v' * S_psi0
     738        14192 :          CALL parallel_gemm('T', 'N', mv, mp, nv, 1.0_dp, v(ispin), S_psi0(ispin), 0.0_dp, buf)
     739              :          ! v = v - psi0 * buf'
     740        14192 :          CALL parallel_gemm('N', 'T', nv, mv, mp, -1.0_dp, psi0(ispin), buf, 1.0_dp, v(ispin))
     741              :          !
     742        66856 :          CALL cp_fm_release(buf)
     743              :       END DO
     744              :       !
     745        10088 :       CALL timestop(handle)
     746              :       !
     747        10088 :    END SUBROUTINE preortho
     748              : 
     749              : ! **************************************************************************************************
     750              : !> \brief projects first index of v onto the virtual subspace
     751              : !> \param v matrix to be projected
     752              : !> \param psi0 matrix with occupied orbitals
     753              : !> \param S_psi0 matrix containing product of metric and occupied orbitals
     754              : ! **************************************************************************************************
     755        61184 :    SUBROUTINE postortho(v, psi0, S_psi0)
     756              :       !v = (I-SP)v
     757              :       !
     758              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: v, psi0, S_psi0
     759              : 
     760              :       CHARACTER(LEN=*), PARAMETER                        :: routineN = 'postortho'
     761              : 
     762              :       INTEGER                                            :: handle, ispin, mp, mt, mv, np, nspins, &
     763              :                                                             nt, nv
     764              :       TYPE(cp_fm_struct_type), POINTER                   :: tmp_fm_struct
     765              :       TYPE(cp_fm_type)                                   :: buf
     766              : 
     767        61184 :       CALL timeset(routineN, handle)
     768              :       !
     769        61184 :       NULLIFY (tmp_fm_struct)
     770              :       !
     771        61184 :       nspins = SIZE(v, 1)
     772              :       !
     773       149700 :       DO ispin = 1, nspins
     774        88516 :          CALL cp_fm_get_info(v(ispin), ncol_global=mv, nrow_global=nv)
     775        88516 :          CALL cp_fm_get_info(psi0(ispin), ncol_global=mp, nrow_global=np)
     776              :          !
     777              :          CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=nv, ncol_global=mp, &
     778              :                                   para_env=v(ispin)%matrix_struct%para_env, &
     779        88516 :                                   context=v(ispin)%matrix_struct%context)
     780        88516 :          CALL cp_fm_create(buf, tmp_fm_struct)
     781        88516 :          CALL cp_fm_struct_release(tmp_fm_struct)
     782              :          !
     783        88516 :          CALL cp_fm_get_info(buf, ncol_global=mt, nrow_global=nt)
     784        88516 :          CPASSERT(nv == np)
     785        88516 :          CPASSERT(mt >= mv)
     786        88516 :          CPASSERT(mt >= mp)
     787        88516 :          CPASSERT(nt == nv)
     788              :          !
     789              :          ! buf = v' * psi0
     790        88516 :          CALL parallel_gemm('T', 'N', mv, mp, nv, 1.0_dp, v(ispin), psi0(ispin), 0.0_dp, buf)
     791              :          ! v = v - S_psi0 * buf'
     792        88516 :          CALL parallel_gemm('N', 'T', nv, mv, mp, -1.0_dp, S_psi0(ispin), buf, 1.0_dp, v(ispin))
     793              :          !
     794       415248 :          CALL cp_fm_release(buf)
     795              :       END DO
     796              :       !
     797        61184 :       CALL timestop(handle)
     798              :       !
     799        61184 :    END SUBROUTINE postortho
     800              : 
     801              : ! **************************************************************************************************
     802              : !> \brief ...
     803              : !> \param qs_env ...
     804              : !> \param linres_section ...
     805              : !> \param vec ...
     806              : !> \param ivec ...
     807              : !> \param tag ...
     808              : !> \param ind ...
     809              : ! **************************************************************************************************
     810         3522 :    SUBROUTINE linres_write_restart(qs_env, linres_section, vec, ivec, tag, ind)
     811              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     812              :       TYPE(section_vals_type), POINTER                   :: linres_section
     813              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: vec
     814              :       INTEGER, INTENT(IN)                                :: ivec
     815              :       CHARACTER(LEN=*)                                   :: tag
     816              :       INTEGER, INTENT(IN), OPTIONAL                      :: ind
     817              : 
     818              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_write_restart'
     819              : 
     820              :       CHARACTER(LEN=default_path_length)                 :: filename
     821              :       CHARACTER(LEN=default_string_length)               :: my_middle, my_pos, my_status
     822              :       INTEGER                                            :: handle, i, i_block, ia, ie, iounit, &
     823              :                                                             ispin, j, max_block, nao, nmo, nspins, &
     824              :                                                             rst_unit
     825         3522 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: vecbuffer
     826              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     827              :       TYPE(cp_logger_type), POINTER                      :: logger
     828         3522 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     829              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     830              :       TYPE(section_vals_type), POINTER                   :: print_key
     831              : 
     832         3522 :       NULLIFY (logger, mo_coeff, mos, para_env, print_key, vecbuffer)
     833              : 
     834         3522 :       CALL timeset(routineN, handle)
     835              : 
     836         3522 :       logger => cp_get_default_logger()
     837              : 
     838         3522 :       IF (BTEST(cp_print_key_should_output(logger%iter_info, linres_section, "PRINT%RESTART", &
     839              :                                            used_print_key=print_key), &
     840              :                 cp_p_file)) THEN
     841              : 
     842              :          iounit = cp_print_key_unit_nr(logger, linres_section, &
     843         3522 :                                        "PRINT%PROGRAM_RUN_INFO", extension=".Log")
     844              : 
     845              :          CALL get_qs_env(qs_env=qs_env, &
     846              :                          mos=mos, &
     847         3522 :                          para_env=para_env)
     848              : 
     849         3522 :          nspins = SIZE(mos)
     850              : 
     851         3522 :          my_status = "REPLACE"
     852         3522 :          my_pos = "REWIND"
     853         3522 :          CALL XSTRING(tag, ia, ie)
     854         3522 :          IF (PRESENT(ind)) THEN
     855         2460 :             my_middle = "RESTART-"//tag(ia:ie)//TRIM(ADJUSTL(cp_to_string(ivec)))
     856              :          ELSE
     857         1062 :             my_middle = "RESTART-"//tag(ia:ie)
     858         1062 :             IF (ivec > 1) THEN
     859          708 :                my_status = "OLD"
     860          708 :                my_pos = "APPEND"
     861              :             END IF
     862              :          END IF
     863              :          rst_unit = cp_print_key_unit_nr(logger, linres_section, "PRINT%RESTART", &
     864              :                                          extension=".lr", middle_name=TRIM(my_middle), file_status=TRIM(my_status), &
     865         3522 :                                          file_position=TRIM(my_pos), file_action="WRITE", file_form="UNFORMATTED")
     866              : 
     867              :          filename = cp_print_key_generate_filename(logger, print_key, &
     868         3522 :                                                    extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
     869              : 
     870         3522 :          IF (iounit > 0) THEN
     871              :             WRITE (UNIT=iounit, FMT="(T2,A)") &
     872         1761 :                "LINRES| Writing response functions to the restart file <"//TRIM(ADJUSTL(filename))//">"
     873              :          END IF
     874              : 
     875              :          !
     876              :          ! write data to file
     877              :          ! use the scalapack block size as a default for buffering columns
     878         3522 :          CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
     879         3522 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
     880        14088 :          ALLOCATE (vecbuffer(nao, max_block))
     881              : 
     882         3522 :          IF (PRESENT(ind)) THEN
     883         2460 :             IF (rst_unit > 0) WRITE (rst_unit) ind, ivec, nspins, nao
     884              :          ELSE
     885         1062 :             IF (rst_unit > 0) WRITE (rst_unit) ivec, nspins, nao
     886              :          END IF
     887              : 
     888         8934 :          DO ispin = 1, nspins
     889         5412 :             CALL cp_fm_get_info(vec(ispin), ncol_global=nmo)
     890              : 
     891         5412 :             IF (rst_unit > 0) WRITE (rst_unit) nmo
     892              : 
     893        22494 :             DO i = 1, nmo, MAX(max_block, 1)
     894         8148 :                i_block = MIN(max_block, nmo - i + 1)
     895         8148 :                CALL cp_fm_get_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
     896              :                ! doing this in one write would increase efficiency, but breaks RESTART compatibility.
     897              :                ! to old ones, and in cases where max_block is different between runs, as might happen during
     898              :                ! restarts with a different number of CPUs
     899        50352 :                DO j = 1, i_block
     900        44940 :                   IF (rst_unit > 0) WRITE (rst_unit) vecbuffer(1:nao, j)
     901              :                END DO
     902              :             END DO
     903              :          END DO
     904              : 
     905         3522 :          DEALLOCATE (vecbuffer)
     906              : 
     907              :          CALL cp_print_key_finished_output(rst_unit, logger, linres_section, &
     908         7044 :                                            "PRINT%RESTART")
     909              :       END IF
     910              : 
     911         3522 :       CALL timestop(handle)
     912              : 
     913         3522 :    END SUBROUTINE linres_write_restart
     914              : 
     915              : ! **************************************************************************************************
     916              : !> \brief ...
     917              : !> \param qs_env ...
     918              : !> \param linres_section ...
     919              : !> \param vec ...
     920              : !> \param ivec ...
     921              : !> \param tag ...
     922              : !> \param ind ...
     923              : ! **************************************************************************************************
     924           72 :    SUBROUTINE linres_read_restart(qs_env, linres_section, vec, ivec, tag, ind)
     925              :       TYPE(qs_environment_type), POINTER                 :: qs_env
     926              :       TYPE(section_vals_type), POINTER                   :: linres_section
     927              :       TYPE(cp_fm_type), DIMENSION(:), INTENT(IN)         :: vec
     928              :       INTEGER, INTENT(IN)                                :: ivec
     929              :       CHARACTER(LEN=*)                                   :: tag
     930              :       INTEGER, INTENT(INOUT), OPTIONAL                   :: ind
     931              : 
     932              :       CHARACTER(LEN=*), PARAMETER :: routineN = 'linres_read_restart'
     933              : 
     934              :       CHARACTER(LEN=default_path_length)                 :: filename
     935              :       CHARACTER(LEN=default_string_length)               :: my_middle
     936              :       INTEGER :: handle, i, i_block, ia, ie, iostat, iounit, ispin, iv, iv1, ivec_tmp, j, &
     937              :          max_block, n_rep_val, nao, nao_tmp, nmo, nmo_tmp, nspins, nspins_tmp, rst_unit
     938              :       LOGICAL                                            :: file_exists
     939           72 :       REAL(KIND=dp), DIMENSION(:, :), POINTER            :: vecbuffer
     940              :       TYPE(cp_fm_type), POINTER                          :: mo_coeff
     941              :       TYPE(cp_logger_type), POINTER                      :: logger
     942           72 :       TYPE(mo_set_type), DIMENSION(:), POINTER           :: mos
     943              :       TYPE(mp_para_env_type), POINTER                    :: para_env
     944              :       TYPE(section_vals_type), POINTER                   :: print_key
     945              : 
     946           72 :       file_exists = .FALSE.
     947              : 
     948           72 :       CALL timeset(routineN, handle)
     949              : 
     950           72 :       NULLIFY (mos, para_env, logger, print_key, vecbuffer)
     951           72 :       logger => cp_get_default_logger()
     952              : 
     953              :       iounit = cp_print_key_unit_nr(logger, linres_section, &
     954           72 :                                     "PRINT%PROGRAM_RUN_INFO", extension=".Log")
     955              : 
     956              :       CALL get_qs_env(qs_env=qs_env, &
     957              :                       para_env=para_env, &
     958           72 :                       mos=mos)
     959              : 
     960           72 :       nspins = SIZE(mos)
     961              : 
     962           72 :       rst_unit = -1
     963           72 :       IF (para_env%is_source()) THEN
     964              :          CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", &
     965           36 :                                    n_rep_val=n_rep_val)
     966              : 
     967           36 :          CALL XSTRING(tag, ia, ie)
     968           36 :          IF (PRESENT(ind)) THEN
     969            9 :             my_middle = "RESTART-"//tag(ia:ie)//TRIM(ADJUSTL(cp_to_string(ivec)))
     970              :          ELSE
     971           27 :             my_middle = "RESTART-"//tag(ia:ie)
     972              :          END IF
     973              : 
     974           36 :          IF (n_rep_val > 0) THEN
     975           18 :             CALL section_vals_val_get(linres_section, "WFN_RESTART_FILE_NAME", c_val=filename)
     976           18 :             CALL xstring(filename, ia, ie)
     977           18 :             filename = filename(ia:ie)//TRIM(my_middle)//".lr"
     978              :          ELSE
     979              :             ! try to read from the filename that is generated automatically from the printkey
     980           18 :             print_key => section_vals_get_subs_vals(linres_section, "PRINT%RESTART")
     981              :             filename = cp_print_key_generate_filename(logger, print_key, &
     982           18 :                                                       extension=".lr", middle_name=TRIM(my_middle), my_local=.FALSE.)
     983              :          END IF
     984           36 :          INQUIRE (FILE=filename, exist=file_exists)
     985              :          !
     986              :          ! open file
     987           36 :          IF (file_exists) THEN
     988              :             CALL open_file(file_name=TRIM(filename), &
     989              :                            file_action="READ", &
     990              :                            file_form="UNFORMATTED", &
     991              :                            file_position="REWIND", &
     992              :                            file_status="OLD", &
     993           15 :                            unit_number=rst_unit)
     994              : 
     995           15 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
     996           15 :                "LINRES| Reading response wavefunctions from the restart file <"//TRIM(ADJUSTL(filename))//">"
     997              :          ELSE
     998           21 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
     999           21 :                "LINRES| Restart file  <"//TRIM(ADJUSTL(filename))//"> not found"
    1000              :          END IF
    1001              :       END IF
    1002              : 
    1003           72 :       CALL para_env%bcast(file_exists)
    1004              : 
    1005           72 :       IF (file_exists) THEN
    1006              : 
    1007           30 :          CALL get_mo_set(mos(1), mo_coeff=mo_coeff)
    1008           30 :          CALL cp_fm_get_info(mo_coeff, nrow_global=nao, ncol_block=max_block)
    1009              : 
    1010          120 :          ALLOCATE (vecbuffer(nao, max_block))
    1011              :          !
    1012              :          ! read headers
    1013           30 :          IF (PRESENT(ind)) THEN
    1014            6 :             iv1 = ivec
    1015              :          ELSE
    1016              :             iv1 = 1
    1017              :          END IF
    1018           54 :          DO iv = iv1, ivec
    1019              : 
    1020           54 :             IF (PRESENT(ind)) THEN
    1021            6 :                IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) ind, ivec_tmp, nspins_tmp, nao_tmp
    1022            6 :                CALL para_env%bcast(iostat)
    1023            6 :                CALL para_env%bcast(ind)
    1024              :             ELSE
    1025           48 :                IF (rst_unit > 0) READ (rst_unit, IOSTAT=iostat) ivec_tmp, nspins_tmp, nao_tmp
    1026           48 :                CALL para_env%bcast(iostat)
    1027              :             END IF
    1028              : 
    1029           54 :             IF (iostat .NE. 0) EXIT
    1030           54 :             CALL para_env%bcast(ivec_tmp)
    1031           54 :             CALL para_env%bcast(nspins_tmp)
    1032           54 :             CALL para_env%bcast(nao_tmp)
    1033              : 
    1034              :             ! check that the number nao, nmo and nspins are
    1035              :             ! the same as in the current mos
    1036           54 :             IF (nspins_tmp .NE. nspins) CPABORT("nspins not consistent")
    1037           54 :             IF (nao_tmp .NE. nao) CPABORT("nao not consistent")
    1038              :             !
    1039          108 :             DO ispin = 1, nspins
    1040           54 :                CALL get_mo_set(mos(ispin), mo_coeff=mo_coeff)
    1041           54 :                CALL cp_fm_get_info(mo_coeff, ncol_global=nmo)
    1042              :                !
    1043           54 :                IF (rst_unit > 0) READ (rst_unit) nmo_tmp
    1044           54 :                CALL para_env%bcast(nmo_tmp)
    1045           54 :                IF (nmo_tmp .NE. nmo) CPABORT("nmo not consistent")
    1046              :                !
    1047              :                ! read the response
    1048          216 :                DO i = 1, nmo, MAX(max_block, 1)
    1049           54 :                   i_block = MIN(max_block, nmo - i + 1)
    1050          270 :                   DO j = 1, i_block
    1051          270 :                      IF (rst_unit > 0) READ (rst_unit) vecbuffer(1:nao, j)
    1052              :                   END DO
    1053          108 :                   IF (iv .EQ. ivec_tmp) THEN
    1054        10422 :                      CALL para_env%bcast(vecbuffer)
    1055           54 :                      CALL cp_fm_set_submatrix(vec(ispin), vecbuffer, 1, i, nao, i_block)
    1056              :                   END IF
    1057              :                END DO
    1058              :             END DO
    1059           54 :             IF (ivec .EQ. ivec_tmp) EXIT
    1060              :          END DO
    1061              : 
    1062           30 :          IF (iostat /= 0) THEN
    1063            0 :             IF (iounit > 0) WRITE (iounit, "(T2,A)") &
    1064            0 :                "LINRES| Restart file <"//TRIM(ADJUSTL(filename))//"> not found"
    1065              :          END IF
    1066              : 
    1067           60 :          DEALLOCATE (vecbuffer)
    1068              : 
    1069              :       END IF
    1070              : 
    1071           72 :       IF (para_env%is_source()) THEN
    1072           36 :          IF (file_exists) CALL close_file(unit_number=rst_unit)
    1073              :       END IF
    1074              : 
    1075           72 :       CALL timestop(handle)
    1076              : 
    1077           72 :    END SUBROUTINE linres_read_restart
    1078              : 
    1079              : ! **************************************************************************************************
    1080              : !> \brief ...
    1081              : !> \param p_env ...
    1082              : !> \param linres_control ...
    1083              : !> \param nspins ...
    1084              : ! **************************************************************************************************
    1085         5044 :    SUBROUTINE check_p_env_init(p_env, linres_control, nspins)
    1086              :       !
    1087              :       TYPE(qs_p_env_type)                                :: p_env
    1088              :       TYPE(linres_control_type), INTENT(IN)              :: linres_control
    1089              :       INTEGER, INTENT(IN)                                :: nspins
    1090              : 
    1091              :       INTEGER                                            :: ispin, ncol, nrow
    1092              : 
    1093         5044 :       IF (linres_control%preconditioner_type /= ot_precond_none) THEN
    1094         5044 :          CPASSERT(ASSOCIATED(p_env%preconditioner))
    1095        12140 :          DO ispin = 1, nspins
    1096         7096 :             CALL cp_fm_get_info(p_env%PS_psi0(ispin), nrow_global=nrow, ncol_global=ncol)
    1097         7096 :             CPASSERT(nrow == p_env%n_ao(ispin))
    1098        19236 :             CPASSERT(ncol == p_env%n_mo(ispin))
    1099              :          END DO
    1100              :       END IF
    1101              : 
    1102         5044 :    END SUBROUTINE check_p_env_init
    1103              : 
    1104              : END MODULE qs_linres_methods
        

Generated by: LCOV version 2.0-1