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 : MODULE qs_tddfpt2_eigensolver
9 : USE cp_blacs_env, ONLY: cp_blacs_env_type
10 : USE cp_control_types, ONLY: tddfpt2_control_type
11 : USE cp_dbcsr_api, ONLY: dbcsr_get_info,&
12 : dbcsr_p_type,&
13 : dbcsr_type
14 : USE cp_dbcsr_operations, ONLY: cp_dbcsr_sm_fm_multiply
15 : USE cp_fm_basic_linalg, ONLY: cp_fm_contracted_trace,&
16 : cp_fm_scale,&
17 : cp_fm_scale_and_add,&
18 : cp_fm_trace
19 : USE cp_fm_diag, ONLY: choose_eigv_solver
20 : USE cp_fm_pool_types, ONLY: fm_pool_create_fm,&
21 : fm_pool_give_back_fm
22 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
23 : cp_fm_struct_release,&
24 : cp_fm_struct_type
25 : USE cp_fm_types, ONLY: &
26 : cp_fm_copy_general, cp_fm_create, cp_fm_get_info, cp_fm_get_submatrix, cp_fm_maxabsval, &
27 : cp_fm_release, cp_fm_set_all, cp_fm_set_submatrix, cp_fm_to_fm, cp_fm_type
28 : USE cp_log_handling, ONLY: cp_logger_type
29 : USE cp_output_handling, ONLY: cp_iterate
30 : USE input_constants, ONLY: tddfpt_kernel_full,&
31 : tddfpt_kernel_none,&
32 : tddfpt_kernel_stda
33 : USE input_section_types, ONLY: section_vals_type
34 : USE kinds, ONLY: dp,&
35 : int_8
36 : USE machine, ONLY: m_flush,&
37 : m_walltime
38 : USE memory_utilities, ONLY: reallocate
39 : USE message_passing, ONLY: mp_para_env_type
40 : USE parallel_gemm_api, ONLY: parallel_gemm
41 : USE physcon, ONLY: evolt
42 : USE qs_environment_types, ONLY: get_qs_env,&
43 : qs_environment_type
44 : USE qs_kernel_types, ONLY: full_kernel_env_type,&
45 : kernel_env_type
46 : USE qs_scf_methods, ONLY: eigensolver
47 : USE qs_tddfpt2_fhxc, ONLY: fhxc_kernel,&
48 : stda_kernel
49 : USE qs_tddfpt2_operators, ONLY: tddfpt_apply_energy_diff,&
50 : tddfpt_apply_hfx,&
51 : tddfpt_apply_hfxlr_kernel,&
52 : tddfpt_apply_hfxsr_kernel
53 : USE qs_tddfpt2_restart, ONLY: tddfpt_write_restart
54 : USE qs_tddfpt2_smearing_methods, ONLY: add_smearing_aterm,&
55 : compute_fermib,&
56 : orthogonalize_smeared_occupation
57 : USE qs_tddfpt2_subgroups, ONLY: tddfpt_subgroup_env_type
58 : USE qs_tddfpt2_types, ONLY: tddfpt_ground_state_mos,&
59 : tddfpt_work_matrices
60 : USE qs_tddfpt2_utils, ONLY: tddfpt_total_number_of_states
61 : #include "./base/base_uses.f90"
62 :
63 : IMPLICIT NONE
64 :
65 : PRIVATE
66 :
67 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_tddfpt2_eigensolver'
68 :
69 : LOGICAL, PARAMETER, PRIVATE :: debug_this_module = .FALSE.
70 : ! number of first derivative components (3: d/dx, d/dy, d/dz)
71 : INTEGER, PARAMETER, PRIVATE :: nderivs = 3
72 : INTEGER, PARAMETER, PRIVATE :: maxspins = 2
73 :
74 : PUBLIC :: tddfpt_davidson_solver, tddfpt_orthogonalize_psi1_psi0, &
75 : tddfpt_orthonormalize_psi1_psi1
76 :
77 : ! **************************************************************************************************
78 :
79 : CONTAINS
80 :
81 : ! **************************************************************************************************
82 : !> \brief Make TDDFPT trial vectors orthogonal to all occupied molecular orbitals.
83 : !> \param evects trial vectors distributed across all processors (modified on exit)
84 : !> \param S_C0_C0T matrix product S * C_0 * C_0^T, where C_0 is the ground state
85 : !> wave function for each spin expressed in atomic basis set,
86 : !> and S is the corresponding overlap matrix
87 : !> \param qs_env ...
88 : !> \param gs_mos ...
89 : !> \param evals ...
90 : !> \param tddfpt_control ...
91 : !> \param S_C0 ...
92 : !> \par History
93 : !> * 05.2016 created [Sergey Chulkov]
94 : !> * 05.2019 use a temporary work matrix [JHU]
95 : !> \note Based on the subroutine p_preortho() which was created by Thomas Chassaing on 09.2002.
96 : !> Should be useless when ground state MOs are computed with extremely high accuracy,
97 : !> as all virtual orbitals are already orthogonal to the occupied ones by design.
98 : !> However, when the norm of residual vectors is relatively small (e.g. less then SCF_EPS),
99 : !> new Krylov's vectors seem to be random and should be orthogonalised even with respect to
100 : !> the occupied MOs.
101 : ! **************************************************************************************************
102 6254 : SUBROUTINE tddfpt_orthogonalize_psi1_psi0(evects, S_C0_C0T, qs_env, gs_mos, evals, &
103 6254 : tddfpt_control, S_C0)
104 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: evects
105 : TYPE(cp_fm_type), DIMENSION(:), INTENT(in) :: S_C0_C0T
106 : TYPE(qs_environment_type), POINTER :: qs_env
107 : TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
108 : INTENT(in) :: gs_mos
109 : REAL(kind=dp), DIMENSION(:), INTENT(in) :: evals
110 : TYPE(tddfpt2_control_type), INTENT(in), POINTER :: tddfpt_control
111 : TYPE(cp_fm_type), DIMENSION(:), INTENT(in) :: S_C0
112 :
113 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_orthogonalize_psi1_psi0'
114 :
115 : INTEGER :: handle, ispin, ivect, nactive, nao, &
116 : nspins, nvects
117 : TYPE(cp_fm_struct_type), POINTER :: matrix_struct
118 : TYPE(cp_fm_type) :: evortho
119 6254 : TYPE(cp_fm_type), DIMENSION(:), POINTER :: mos
120 : TYPE(mp_para_env_type), POINTER :: para_env
121 :
122 6254 : CALL timeset(routineN, handle)
123 :
124 6254 : nspins = SIZE(evects, 1)
125 6254 : nvects = SIZE(evects, 2)
126 :
127 6254 : IF (nvects > 0) THEN
128 6254 : IF (.NOT. tddfpt_control%do_smearing) THEN
129 13282 : DO ispin = 1, nspins
130 : CALL cp_fm_get_info(matrix=evects(ispin, 1), matrix_struct=matrix_struct, &
131 7042 : nrow_global=nao, ncol_global=nactive)
132 7042 : CALL cp_fm_create(evortho, matrix_struct)
133 25600 : DO ivect = 1, nvects
134 : ! evortho: C0 * C0^T * S * C1 == (S * C0 * C0^T)^T * C1
135 : CALL parallel_gemm('T', 'N', nao, nactive, nao, 1.0_dp, S_C0_C0T(ispin), &
136 18558 : evects(ispin, ivect), 0.0_dp, evortho)
137 25600 : CALL cp_fm_scale_and_add(1.0_dp, evects(ispin, ivect), -1.0_dp, evortho)
138 : END DO
139 20324 : CALL cp_fm_release(evortho)
140 : END DO
141 : ELSE
142 14 : NULLIFY (para_env)
143 14 : CALL get_qs_env(qs_env, para_env=para_env)
144 14 : NULLIFY (mos)
145 56 : ALLOCATE (mos(nspins))
146 28 : DO ispin = 1, nspins
147 : CALL cp_fm_get_info(matrix=evects(ispin, 1), matrix_struct=matrix_struct, &
148 14 : nrow_global=nao, ncol_global=nactive)
149 14 : CALL cp_fm_create(mos(ispin), matrix_struct)
150 42 : CALL cp_fm_copy_general(gs_mos(ispin)%mos_occ, mos(ispin), para_env)
151 : END DO
152 28 : DO ivect = 1, nvects
153 14 : CALL compute_fermib(qs_env, gs_mos, evals(ivect))
154 28 : CALL orthogonalize_smeared_occupation(evects(:, ivect), qs_env, mos, S_C0)
155 : END DO
156 28 : DO ispin = 1, nspins
157 28 : CALL cp_fm_release(mos(ispin))
158 : END DO
159 14 : DEALLOCATE (mos)
160 : END IF
161 : END IF
162 :
163 6254 : CALL timestop(handle)
164 :
165 6254 : END SUBROUTINE tddfpt_orthogonalize_psi1_psi0
166 :
167 : ! **************************************************************************************************
168 : !> \brief Check that orthogonalised TDDFPT trial vectors remain orthogonal to
169 : !> occupied molecular orbitals.
170 : !> \param evects trial vectors
171 : !> \param S_C0 matrix product S * C_0, where C_0 is the ground state wave function
172 : !> for each spin in atomic basis set, and S is the corresponding overlap matrix
173 : !> \param max_norm the largest possible overlap between the ground state and
174 : !> excited state wave functions
175 : !> \return true if trial vectors are non-orthogonal to occupied molecular orbitals
176 : !> \par History
177 : !> * 07.2016 created [Sergey Chulkov]
178 : !> * 05.2019 use temporary work matrices [JHU]
179 : ! **************************************************************************************************
180 4038 : FUNCTION tddfpt_is_nonorthogonal_psi1_psi0(evects, S_C0, max_norm) &
181 : RESULT(is_nonortho)
182 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: evects
183 : TYPE(cp_fm_type), DIMENSION(:), INTENT(in) :: S_C0
184 : REAL(kind=dp), INTENT(in) :: max_norm
185 : LOGICAL :: is_nonortho
186 :
187 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_is_nonorthogonal_psi1_psi0'
188 :
189 : INTEGER :: handle, ispin, ivect, nactive, nao, &
190 : nocc, nspins, nvects
191 : REAL(kind=dp) :: maxabs_val
192 : TYPE(cp_fm_struct_type), POINTER :: matrix_struct, matrix_struct_tmp
193 : TYPE(cp_fm_type) :: aortho
194 :
195 4038 : CALL timeset(routineN, handle)
196 :
197 4038 : nspins = SIZE(evects, 1)
198 4038 : nvects = SIZE(evects, 2)
199 :
200 4038 : is_nonortho = .FALSE.
201 :
202 8626 : loop: DO ispin = 1, nspins
203 4592 : CALL cp_fm_get_info(matrix=S_C0(ispin), ncol_global=nocc)
204 : CALL cp_fm_get_info(matrix=evects(ispin, 1), matrix_struct=matrix_struct, &
205 4592 : nrow_global=nao, ncol_global=nactive)
206 : CALL cp_fm_struct_create(matrix_struct_tmp, nrow_global=nocc, &
207 4592 : ncol_global=nactive, template_fmstruct=matrix_struct)
208 4592 : CALL cp_fm_create(aortho, matrix_struct_tmp)
209 4592 : CALL cp_fm_struct_release(matrix_struct_tmp)
210 16204 : DO ivect = 1, nvects
211 : ! aortho = S_0^T * S * C_1
212 : CALL parallel_gemm('T', 'N', nocc, nactive, nao, 1.0_dp, S_C0(ispin), &
213 11616 : evects(ispin, ivect), 0.0_dp, aortho)
214 11616 : CALL cp_fm_maxabsval(aortho, maxabs_val)
215 11616 : is_nonortho = maxabs_val > max_norm
216 16204 : IF (is_nonortho) THEN
217 4 : CALL cp_fm_release(aortho)
218 4 : EXIT loop
219 : END IF
220 : END DO
221 17806 : CALL cp_fm_release(aortho)
222 : END DO loop
223 :
224 4038 : CALL timestop(handle)
225 :
226 4038 : END FUNCTION tddfpt_is_nonorthogonal_psi1_psi0
227 :
228 : ! **************************************************************************************************
229 : !> \brief Make new TDDFPT trial vectors orthonormal to all previous trial vectors.
230 : !> \param evects trial vectors (modified on exit)
231 : !> \param nvects_new number of new trial vectors to orthogonalise
232 : !> \param S_evects set of matrices to store matrix product S * evects (modified on exit)
233 : !> \param matrix_s overlap matrix
234 : !> \par History
235 : !> * 05.2016 created [Sergey Chulkov]
236 : !> * 02.2017 caching the matrix product S * evects [Sergey Chulkov]
237 : !> \note \parblock
238 : !> Based on the subroutines reorthogonalize() and normalize() which were originally created
239 : !> by Thomas Chassaing on 03.2003.
240 : !>
241 : !> In order to orthogonalise a trial vector C3 = evects(:,3) with respect to previously
242 : !> orthogonalised vectors C1 = evects(:,1) and C2 = evects(:,2) we need to compute the
243 : !> quantity C3'' using the following formulae:
244 : !> C3' = C3 - Tr(C3^T * S * C1) * C1,
245 : !> C3'' = C3' - Tr(C3'^T * S * C2) * C2,
246 : !> which can be expanded as:
247 : !> C3'' = C3 - Tr(C3^T * S * C1) * C1 - Tr(C3^T * S * C2) * C2 +
248 : !> Tr(C3^T * S * C1) * Tr(C2^T * S * C1) * C2 .
249 : !> In case of unlimited float-point precision, the last term in above expression is exactly 0,
250 : !> due to orthogonality condition between C1 and C2. In this case the expression could be
251 : !> simplified as (taking into account the identity: Tr(A * S * B) = Tr(B * S * A)):
252 : !> C3'' = C3 - Tr(C1^T * S * C3) * C1 - Tr(C2^T * S * C3) * C2 ,
253 : !> which means we do not need the variable S_evects to keep the matrix products S * Ci .
254 : !>
255 : !> In reality, however, we deal with limited float-point precision arithmetic meaning that
256 : !> the trace Tr(C2^T * S * C1) is close to 0 but does not equal to 0 exactly. The term
257 : !> Tr(C3^T * S * C1) * Tr(C2^T * S * C1) * C2
258 : !> can not be ignored anymore. Ignorance of this term will lead to numerical instability
259 : !> when the trace Tr(C3^T * S * C1) is large enough.
260 : !> \endparblock
261 : ! **************************************************************************************************
262 6254 : SUBROUTINE tddfpt_orthonormalize_psi1_psi1(evects, nvects_new, S_evects, matrix_s)
263 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: evects
264 : INTEGER, INTENT(in) :: nvects_new
265 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: S_evects
266 : TYPE(dbcsr_type), POINTER :: matrix_s
267 :
268 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_orthonormalize_psi1_psi1'
269 :
270 : INTEGER :: handle, ispin, ivect, jvect, nspins, &
271 : nvects_old, nvects_total
272 : INTEGER, DIMENSION(maxspins) :: nactive
273 : REAL(kind=dp) :: norm
274 : REAL(kind=dp), DIMENSION(maxspins) :: weights
275 :
276 6254 : CALL timeset(routineN, handle)
277 :
278 6254 : nspins = SIZE(evects, 1)
279 6254 : nvects_total = SIZE(evects, 2)
280 6254 : nvects_old = nvects_total - nvects_new
281 :
282 : IF (debug_this_module) THEN
283 : CPASSERT(SIZE(S_evects, 1) == nspins)
284 : CPASSERT(SIZE(S_evects, 2) == nvects_total)
285 : CPASSERT(nvects_old >= 0)
286 : END IF
287 :
288 13310 : DO ispin = 1, nspins
289 13310 : CALL cp_fm_get_info(matrix=evects(ispin, 1), ncol_global=nactive(ispin))
290 : END DO
291 :
292 22420 : DO jvect = nvects_old + 1, nvects_total
293 : ! <psi1_i | psi1_j>
294 138878 : DO ivect = 1, jvect - 1
295 122712 : CALL cp_fm_trace(evects(:, jvect), S_evects(:, ivect), weights(1:nspins), accurate=.FALSE.)
296 266520 : norm = SUM(weights(1:nspins))
297 :
298 282686 : DO ispin = 1, nspins
299 266520 : CALL cp_fm_scale_and_add(1.0_dp, evects(ispin, jvect), -norm, evects(ispin, ivect))
300 : END DO
301 : END DO
302 :
303 : ! <psi1_j | psi1_j>
304 34738 : DO ispin = 1, nspins
305 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, evects(ispin, jvect), S_evects(ispin, jvect), &
306 34738 : ncol=nactive(ispin), alpha=1.0_dp, beta=0.0_dp)
307 : END DO
308 :
309 16166 : CALL cp_fm_trace(evects(:, jvect), S_evects(:, jvect), weights(1:nspins), accurate=.FALSE.)
310 :
311 34738 : norm = SUM(weights(1:nspins))
312 16166 : norm = 1.0_dp/SQRT(norm)
313 :
314 40992 : DO ispin = 1, nspins
315 18572 : CALL cp_fm_scale(norm, evects(ispin, jvect))
316 34738 : CALL cp_fm_scale(norm, S_evects(ispin, jvect))
317 : END DO
318 : END DO
319 :
320 6254 : CALL timestop(handle)
321 :
322 6254 : END SUBROUTINE tddfpt_orthonormalize_psi1_psi1
323 :
324 : ! **************************************************************************************************
325 : !> \brief Compute action matrix-vector products.
326 : !> \param Aop_evects action of TDDFPT operator on trial vectors (modified on exit)
327 : !> \param evects TDDFPT trial vectors
328 : !> \param S_evects cached matrix product S * evects where S is the overlap matrix
329 : !> in primary basis set
330 : !> \param gs_mos molecular orbitals optimised for the ground state
331 : !> \param tddfpt_control control section for tddfpt
332 : !> \param matrix_ks Kohn-Sham matrix
333 : !> \param qs_env Quickstep environment
334 : !> \param kernel_env kernel environment
335 : !> \param sub_env parallel (sub)group environment
336 : !> \param work_matrices collection of work matrices (modified on exit)
337 : !> \param matrix_s ...
338 : !> \par History
339 : !> * 06.2016 created [Sergey Chulkov]
340 : !> * 03.2017 refactored [Sergey Chulkov]
341 : ! **************************************************************************************************
342 5184 : SUBROUTINE tddfpt_compute_Aop_evects(Aop_evects, evects, S_evects, gs_mos, tddfpt_control, &
343 5184 : matrix_ks, qs_env, kernel_env, &
344 : sub_env, work_matrices, matrix_s)
345 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: Aop_evects, evects, S_evects
346 : TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
347 : INTENT(in) :: gs_mos
348 : TYPE(tddfpt2_control_type), POINTER :: tddfpt_control
349 : TYPE(dbcsr_p_type), DIMENSION(:), INTENT(in) :: matrix_ks
350 : TYPE(qs_environment_type), POINTER :: qs_env
351 : TYPE(kernel_env_type), INTENT(in) :: kernel_env
352 : TYPE(tddfpt_subgroup_env_type), INTENT(in) :: sub_env
353 : TYPE(tddfpt_work_matrices), INTENT(inout) :: work_matrices
354 : TYPE(dbcsr_type), POINTER :: matrix_s
355 :
356 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_compute_Aop_evects'
357 :
358 : INTEGER :: handle, ispin, ivect, nspins, nvects
359 : INTEGER, DIMENSION(maxspins) :: nmo_occ
360 : LOGICAL :: do_admm, do_hfx, do_lri_response, &
361 : is_rks_triplets, re_int
362 : REAL(KIND=dp) :: rcut, scale
363 : TYPE(cp_fm_type) :: fm_dummy
364 : TYPE(full_kernel_env_type), POINTER :: kernel_env_admm_aux
365 : TYPE(mp_para_env_type), POINTER :: para_env
366 :
367 5184 : CALL timeset(routineN, handle)
368 :
369 5184 : nspins = SIZE(evects, 1)
370 5184 : nvects = SIZE(evects, 2)
371 5184 : do_hfx = tddfpt_control%do_hfx
372 5184 : do_admm = tddfpt_control%do_admm
373 5184 : IF (do_admm) THEN
374 604 : kernel_env_admm_aux => kernel_env%admm_kernel
375 : ELSE
376 4580 : NULLIFY (kernel_env_admm_aux)
377 : END IF
378 5184 : is_rks_triplets = tddfpt_control%rks_triplets
379 5184 : do_lri_response = tddfpt_control%do_lrigpw
380 :
381 : IF (debug_this_module) THEN
382 : CPASSERT(nspins > 0)
383 : CPASSERT(SIZE(Aop_evects, 1) == nspins)
384 : CPASSERT(SIZE(Aop_evects, 2) == nvects)
385 : CPASSERT(SIZE(S_evects, 1) == nspins)
386 : CPASSERT(SIZE(S_evects, 2) == nvects)
387 : CPASSERT(SIZE(gs_mos) == nspins)
388 : END IF
389 :
390 11046 : DO ispin = 1, nspins
391 5184 : nmo_occ(ispin) = SIZE(gs_mos(ispin)%evals_occ)
392 : END DO
393 :
394 5184 : IF (nvects > 0) THEN
395 5184 : CALL cp_fm_get_info(evects(1, 1), para_env=para_env)
396 5184 : IF (ALLOCATED(work_matrices%evects_sub)) THEN
397 24 : DO ivect = 1, nvects
398 40 : DO ispin = 1, nspins
399 16 : ASSOCIATE (evect => evects(ispin, ivect), work_matrix => work_matrices%evects_sub(ispin, ivect))
400 16 : IF (ASSOCIATED(evect%matrix_struct)) THEN
401 16 : IF (ASSOCIATED(work_matrix%matrix_struct)) THEN
402 8 : CALL cp_fm_copy_general(evect, work_matrix, para_env)
403 : ELSE
404 8 : CALL cp_fm_copy_general(evect, fm_dummy, para_env)
405 : END IF
406 0 : ELSE IF (ASSOCIATED(work_matrix%matrix_struct)) THEN
407 0 : CALL cp_fm_copy_general(fm_dummy, work_matrix, para_env)
408 : ELSE
409 0 : CALL cp_fm_copy_general(fm_dummy, fm_dummy, para_env)
410 : END IF
411 : END ASSOCIATE
412 : END DO
413 : END DO
414 : END IF
415 :
416 5184 : IF (tddfpt_control%kernel == tddfpt_kernel_full) THEN
417 : ! full TDDFPT kernel
418 : CALL fhxc_kernel(Aop_evects, evects, is_rks_triplets, do_hfx, do_admm, qs_env, &
419 : kernel_env%full_kernel, kernel_env_admm_aux, sub_env, work_matrices, &
420 : tddfpt_control%admm_symm, tddfpt_control%admm_xc_correction, &
421 2822 : do_lri_response)
422 2362 : ELSE IF (tddfpt_control%kernel == tddfpt_kernel_stda) THEN
423 : ! sTDA kernel
424 : CALL stda_kernel(Aop_evects, evects, is_rks_triplets, qs_env, tddfpt_control%stda_control, &
425 2268 : kernel_env%stda_kernel, sub_env, work_matrices)
426 94 : ELSE IF (tddfpt_control%kernel == tddfpt_kernel_none) THEN
427 : ! No kernel
428 340 : DO ivect = 1, nvects
429 586 : DO ispin = 1, nspins
430 492 : CALL cp_fm_set_all(Aop_evects(ispin, ivect), 0.0_dp)
431 : END DO
432 : END DO
433 : ELSE
434 0 : CPABORT("Kernel type not implemented")
435 : END IF
436 :
437 5184 : IF (ALLOCATED(work_matrices%evects_sub)) THEN
438 24 : DO ivect = 1, nvects
439 40 : DO ispin = 1, nspins
440 : ASSOCIATE (Aop_evect => Aop_evects(ispin, ivect), &
441 16 : work_matrix => work_matrices%Aop_evects_sub(ispin, ivect))
442 16 : IF (ASSOCIATED(Aop_evect%matrix_struct)) THEN
443 16 : IF (ASSOCIATED(work_matrix%matrix_struct)) THEN
444 8 : CALL cp_fm_copy_general(work_matrix, Aop_evect, para_env)
445 : ELSE
446 8 : CALL cp_fm_copy_general(fm_dummy, Aop_evect, para_env)
447 : END IF
448 0 : ELSE IF (ASSOCIATED(work_matrix%matrix_struct)) THEN
449 0 : CALL cp_fm_copy_general(work_matrix, fm_dummy, para_env)
450 : ELSE
451 0 : CALL cp_fm_copy_general(fm_dummy, fm_dummy, para_env)
452 : END IF
453 : END ASSOCIATE
454 : END DO
455 : END DO
456 : END IF
457 :
458 : ! orbital energy difference term
459 : CALL tddfpt_apply_energy_diff(Aop_evects=Aop_evects, evects=evects, S_evects=S_evects, &
460 5184 : gs_mos=gs_mos, matrix_ks=matrix_ks)
461 :
462 : ! if smeared occupation, then add aCCSX here
463 5184 : IF (tddfpt_control%do_smearing) THEN
464 24 : DO ivect = 1, nvects
465 36 : DO ispin = 1, nspins
466 : CALL add_smearing_aterm(qs_env, Aop_evects(ispin, ivect), evects(ispin, ivect), &
467 : S_evects(ispin, ivect), gs_mos(ispin)%mos_occ, &
468 24 : tddfpt_control%smeared_occup(ispin)%fermia, matrix_s)
469 : END DO
470 : END DO
471 : END IF
472 :
473 5184 : IF (do_hfx) THEN
474 1110 : IF (tddfpt_control%kernel == tddfpt_kernel_full) THEN
475 : ! full TDDFPT kernel
476 : CALL tddfpt_apply_hfx(Aop_evects=Aop_evects, evects=evects, gs_mos=gs_mos, do_admm=do_admm, &
477 : qs_env=qs_env, wfm_rho_orb=work_matrices%hfx_fm_ao_ao, &
478 : work_hmat_symm=work_matrices%hfx_hmat_symm, &
479 : work_hmat_asymm=work_matrices%hfx_hmat_asymm, &
480 : work_rho_ia_ao_symm=work_matrices%hfx_rho_ao_symm, &
481 1110 : work_rho_ia_ao_asymm=work_matrices%hfx_rho_ao_asymm)
482 0 : ELSE IF (tddfpt_control%kernel == tddfpt_kernel_stda) THEN
483 : ! sTDA kernel
484 : ! special treatment of HFX term
485 0 : ELSE IF (tddfpt_control%kernel == tddfpt_kernel_none) THEN
486 : ! No kernel
487 : ! drop kernel contribution of HFX term
488 : ELSE
489 0 : CPABORT("Kernel type not implemented")
490 : END IF
491 : END IF
492 : ! short/long range HFX
493 5184 : IF (tddfpt_control%kernel == tddfpt_kernel_full) THEN
494 2822 : IF (tddfpt_control%do_hfxsr) THEN
495 22 : re_int = tddfpt_control%hfxsr_re_int
496 : ! symmetric dmat
497 : CALL tddfpt_apply_hfxsr_kernel(Aop_evects, evects, gs_mos, qs_env, &
498 : kernel_env%full_kernel%admm_env, &
499 : kernel_env%full_kernel%hfxsr_section, &
500 : kernel_env%full_kernel%x_data, 1, re_int, &
501 : work_rho_ia_ao=work_matrices%hfxsr_rho_ao_symm, &
502 : work_hmat=work_matrices%hfxsr_hmat_symm, &
503 22 : wfm_rho_orb=work_matrices%hfxsr_fm_ao_ao)
504 : ! antisymmetric dmat
505 : CALL tddfpt_apply_hfxsr_kernel(Aop_evects, evects, gs_mos, qs_env, &
506 : kernel_env%full_kernel%admm_env, &
507 : kernel_env%full_kernel%hfxsr_section, &
508 : kernel_env%full_kernel%x_data, -1, .FALSE., &
509 : work_rho_ia_ao=work_matrices%hfxsr_rho_ao_asymm, &
510 : work_hmat=work_matrices%hfxsr_hmat_asymm, &
511 22 : wfm_rho_orb=work_matrices%hfxsr_fm_ao_ao)
512 22 : tddfpt_control%hfxsr_re_int = .FALSE.
513 : END IF
514 2822 : IF (tddfpt_control%do_hfxlr) THEN
515 36 : rcut = tddfpt_control%hfxlr_rcut
516 36 : scale = tddfpt_control%hfxlr_scale
517 108 : DO ivect = 1, nvects
518 108 : IF (ALLOCATED(work_matrices%evects_sub)) THEN
519 0 : IF (ASSOCIATED(work_matrices%evects_sub(1, ivect)%matrix_struct)) THEN
520 : CALL tddfpt_apply_hfxlr_kernel(qs_env, sub_env, rcut, scale, work_matrices, &
521 : work_matrices%evects_sub(:, ivect), &
522 0 : work_matrices%Aop_evects_sub(:, ivect))
523 : ELSE
524 : ! skip trial vectors which are assigned to different parallel groups
525 : CYCLE
526 : END IF
527 : ELSE
528 : CALL tddfpt_apply_hfxlr_kernel(qs_env, sub_env, rcut, scale, work_matrices, &
529 72 : evects(:, ivect), Aop_evects(:, ivect))
530 : END IF
531 : END DO
532 : END IF
533 : END IF
534 :
535 : END IF
536 :
537 5184 : CALL timestop(handle)
538 :
539 5184 : END SUBROUTINE tddfpt_compute_Aop_evects
540 :
541 : ! **************************************************************************************************
542 : !> \brief Solve eigenproblem for the reduced action matrix and find new Ritz eigenvectors and
543 : !> eigenvalues.
544 : !> \param ritz_vects Ritz eigenvectors (initialised on exit)
545 : !> \param Aop_ritz approximate action of TDDFPT operator on Ritz vectors (initialised on exit)
546 : !> \param evals Ritz eigenvalues (initialised on exit)
547 : !> \param krylov_vects Krylov's vectors
548 : !> \param Aop_krylov action of TDDFPT operator on Krylov's vectors
549 : !> \param Atilde ...
550 : !> \param nkvo ...
551 : !> \param nkvn ...
552 : !> \par History
553 : !> * 06.2016 created [Sergey Chulkov]
554 : !> * 03.2017 altered prototype, OpenMP parallelisation [Sergey Chulkov]
555 : ! **************************************************************************************************
556 5184 : SUBROUTINE tddfpt_compute_ritz_vects(ritz_vects, Aop_ritz, evals, krylov_vects, Aop_krylov, &
557 : Atilde, nkvo, nkvn)
558 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN) :: ritz_vects, Aop_ritz
559 : REAL(kind=dp), DIMENSION(:), INTENT(out) :: evals
560 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(IN) :: krylov_vects, Aop_krylov
561 : REAL(kind=dp), DIMENSION(:, :), POINTER :: Atilde
562 : INTEGER, INTENT(IN) :: nkvo, nkvn
563 :
564 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_compute_ritz_vects'
565 :
566 : INTEGER :: handle, ikv, irv, ispin, nkvs, nrvs, &
567 : nspins
568 : REAL(kind=dp) :: act
569 5184 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: at12, at21, at22, evects_Atilde
570 : TYPE(cp_blacs_env_type), POINTER :: blacs_env_global
571 : TYPE(cp_fm_struct_type), POINTER :: fm_struct
572 : TYPE(cp_fm_type) :: Atilde_fm, evects_Atilde_fm
573 :
574 5184 : CALL timeset(routineN, handle)
575 :
576 5184 : nspins = SIZE(krylov_vects, 1)
577 5184 : nkvs = SIZE(krylov_vects, 2)
578 5184 : nrvs = SIZE(ritz_vects, 2)
579 5184 : CPASSERT(nkvs == nkvo + nkvn)
580 :
581 5184 : CALL cp_fm_get_info(krylov_vects(1, 1), context=blacs_env_global)
582 :
583 5184 : CALL cp_fm_struct_create(fm_struct, nrow_global=nkvs, ncol_global=nkvs, context=blacs_env_global)
584 5184 : CALL cp_fm_create(Atilde_fm, fm_struct)
585 5184 : CALL cp_fm_create(evects_Atilde_fm, fm_struct)
586 5184 : CALL cp_fm_struct_release(fm_struct)
587 :
588 : ! *** compute upper-diagonal reduced action matrix ***
589 5184 : CALL reallocate(Atilde, 1, nkvs, 1, nkvs)
590 : ! TO DO: the subroutine 'cp_fm_contracted_trace' will compute all elements of
591 : ! the matrix 'Atilde', however only upper-triangular elements are actually needed
592 : !
593 5184 : IF (nkvo == 0) THEN
594 : CALL cp_fm_contracted_trace(Aop_krylov(:, 1:nkvs), krylov_vects(:, 1:nkvs), &
595 1150 : Atilde(1:nkvs, 1:nkvs), accurate=.FALSE.)
596 : ELSE
597 36306 : ALLOCATE (at12(nkvn, nkvo), at21(nkvo, nkvn), at22(nkvn, nkvn))
598 : CALL cp_fm_contracted_trace(Aop_krylov(:, nkvo + 1:nkvs), krylov_vects(:, 1:nkvo), &
599 4034 : at12, accurate=.FALSE.)
600 135510 : Atilde(nkvo + 1:nkvs, 1:nkvo) = at12(1:nkvn, 1:nkvo)
601 : CALL cp_fm_contracted_trace(Aop_krylov(:, 1:nkvo), krylov_vects(:, nkvo + 1:nkvs), &
602 4034 : at21, accurate=.FALSE.)
603 112868 : Atilde(1:nkvo, nkvo + 1:nkvs) = at21(1:nkvo, 1:nkvn)
604 : CALL cp_fm_contracted_trace(Aop_krylov(:, nkvo + 1:nkvs), krylov_vects(:, nkvo + 1:nkvs), &
605 4034 : at22, accurate=.FALSE.)
606 51218 : Atilde(nkvo + 1:nkvs, nkvo + 1:nkvs) = at22(1:nkvn, 1:nkvn)
607 4034 : DEALLOCATE (at12, at21, at22)
608 : END IF
609 1587664 : Atilde = 0.5_dp*(Atilde + TRANSPOSE(Atilde))
610 5184 : CALL cp_fm_set_submatrix(Atilde_fm, Atilde)
611 :
612 : ! *** solve an eigenproblem for the reduced matrix ***
613 5184 : CALL choose_eigv_solver(Atilde_fm, evects_Atilde_fm, evals(1:nkvs))
614 :
615 20736 : ALLOCATE (evects_Atilde(nkvs, nrvs))
616 5184 : CALL cp_fm_get_submatrix(evects_Atilde_fm, evects_Atilde, start_row=1, start_col=1, n_rows=nkvs, n_cols=nrvs)
617 5184 : CALL cp_fm_release(evects_Atilde_fm)
618 5184 : CALL cp_fm_release(Atilde_fm)
619 :
620 : !$OMP PARALLEL DO DEFAULT(NONE), &
621 : !$OMP PRIVATE(act, ikv, irv, ispin), &
622 5184 : !$OMP SHARED(Aop_krylov, Aop_ritz, krylov_vects, evects_Atilde, nkvs, nrvs, nspins, ritz_vects)
623 : DO irv = 1, nrvs
624 : DO ispin = 1, nspins
625 : CALL cp_fm_set_all(ritz_vects(ispin, irv), 0.0_dp)
626 : CALL cp_fm_set_all(Aop_ritz(ispin, irv), 0.0_dp)
627 : END DO
628 :
629 : DO ikv = 1, nkvs
630 : act = evects_Atilde(ikv, irv)
631 : DO ispin = 1, nspins
632 : CALL cp_fm_scale_and_add(1.0_dp, ritz_vects(ispin, irv), &
633 : act, krylov_vects(ispin, ikv))
634 : CALL cp_fm_scale_and_add(1.0_dp, Aop_ritz(ispin, irv), &
635 : act, Aop_krylov(ispin, ikv))
636 : END DO
637 : END DO
638 : END DO
639 : !$OMP END PARALLEL DO
640 :
641 5184 : DEALLOCATE (evects_Atilde)
642 :
643 5184 : CALL timestop(handle)
644 :
645 15552 : END SUBROUTINE tddfpt_compute_ritz_vects
646 :
647 : ! **************************************************************************************************
648 : !> \brief Expand Krylov space by computing residual vectors.
649 : !> \param residual_vects residual vectors (modified on exit)
650 : !> \param evals Ritz eigenvalues (modified on exit)
651 : !> \param ritz_vects Ritz eigenvectors
652 : !> \param Aop_ritz approximate action of TDDFPT operator on Ritz vectors
653 : !> \param gs_mos molecular orbitals optimised for the ground state
654 : !> \param matrix_s overlap matrix
655 : !> \par History
656 : !> * 06.2016 created [Sergey Chulkov]
657 : !> * 03.2017 refactored to achieve significant performance gain [Sergey Chulkov]
658 : ! **************************************************************************************************
659 4038 : SUBROUTINE tddfpt_compute_residual_vects(residual_vects, evals, ritz_vects, Aop_ritz, gs_mos, &
660 : matrix_s)
661 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: residual_vects
662 : REAL(kind=dp), DIMENSION(:), INTENT(in) :: evals
663 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(in) :: ritz_vects, Aop_ritz
664 : TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
665 : INTENT(in) :: gs_mos
666 : TYPE(dbcsr_type), POINTER :: matrix_s
667 :
668 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_compute_residual_vects'
669 : REAL(kind=dp), PARAMETER :: eref_scale = 0.99_dp, threshold = 16.0_dp*EPSILON(1.0_dp)
670 :
671 : INTEGER :: handle, icol_local, irow_local, irv, &
672 : ispin, nao, ncols_local, nrows_local, &
673 : nrvs, nspins
674 4038 : INTEGER, DIMENSION(:), POINTER :: col_indices_local, row_indices_local
675 : INTEGER, DIMENSION(maxspins) :: nactive, nmo_virt
676 : REAL(kind=dp) :: e_occ_plus_lambda, eref, lambda
677 : REAL(kind=dp), CONTIGUOUS, DIMENSION(:, :), &
678 4038 : POINTER :: weights_ldata
679 : TYPE(cp_fm_struct_type), POINTER :: ao_mo_struct, virt_mo_struct
680 4038 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:) :: awork, vomat
681 :
682 4038 : CALL timeset(routineN, handle)
683 :
684 4038 : nspins = SIZE(residual_vects, 1)
685 4038 : nrvs = SIZE(residual_vects, 2)
686 :
687 4038 : IF (nrvs > 0) THEN
688 4038 : CALL dbcsr_get_info(matrix_s, nfullrows_total=nao)
689 29374 : ALLOCATE (awork(nspins), vomat(nspins))
690 8630 : DO ispin = 1, nspins
691 4592 : nmo_virt(ispin) = SIZE(gs_mos(ispin)%evals_virt)
692 : !
693 : CALL cp_fm_get_info(matrix=ritz_vects(ispin, 1), matrix_struct=ao_mo_struct, &
694 4592 : ncol_global=nactive(ispin))
695 4592 : CALL cp_fm_create(awork(ispin), ao_mo_struct)
696 : !
697 : CALL cp_fm_struct_create(virt_mo_struct, nrow_global=nmo_virt(ispin), &
698 4592 : ncol_global=nactive(ispin), template_fmstruct=ao_mo_struct)
699 4592 : CALL cp_fm_create(vomat(ispin), virt_mo_struct)
700 8630 : CALL cp_fm_struct_release(virt_mo_struct)
701 : END DO
702 :
703 : ! *** actually compute residual vectors ***
704 14018 : DO irv = 1, nrvs
705 9980 : lambda = evals(irv)
706 :
707 25648 : DO ispin = 1, nspins
708 : CALL cp_fm_get_info(vomat(ispin), nrow_local=nrows_local, &
709 : ncol_local=ncols_local, row_indices=row_indices_local, &
710 11630 : col_indices=col_indices_local, local_data=weights_ldata)
711 :
712 : ! awork := Ab(ispin, irv) - evals(irv) b(ispin, irv), where 'b' is a Ritz vector
713 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, ritz_vects(ispin, irv), awork(ispin), &
714 11630 : ncol=nactive(ispin), alpha=-lambda, beta=0.0_dp)
715 11630 : CALL cp_fm_scale_and_add(1.0_dp, awork(ispin), 1.0_dp, Aop_ritz(ispin, irv))
716 : !
717 : CALL parallel_gemm('T', 'N', nmo_virt(ispin), nactive(ispin), nao, 1.0_dp, gs_mos(ispin)%mos_virt, &
718 11630 : awork(ispin), 0.0_dp, vomat(ispin))
719 :
720 104592 : DO icol_local = 1, ncols_local
721 92962 : e_occ_plus_lambda = gs_mos(ispin)%evals_occ(col_indices_local(icol_local)) + lambda
722 :
723 3396809 : DO irow_local = 1, nrows_local
724 3292217 : eref = gs_mos(ispin)%evals_virt(row_indices_local(irow_local)) - e_occ_plus_lambda
725 :
726 : ! eref = e_virt - e_occ - lambda = e_virt - e_occ - (eref_scale*lambda + (1-eref_scale)*lambda);
727 : ! eref_new = e_virt - e_occ - eref_scale*lambda = eref + (1 - eref_scale)*lambda
728 3292217 : IF (ABS(eref) < threshold) &
729 74 : eref = eref + (1.0_dp - eref_scale)*lambda
730 :
731 3385179 : weights_ldata(irow_local, icol_local) = weights_ldata(irow_local, icol_local)/eref
732 : END DO
733 : END DO
734 :
735 : CALL parallel_gemm('N', 'N', nao, nactive(ispin), nmo_virt(ispin), 1.0_dp, gs_mos(ispin)%mos_virt, &
736 33240 : vomat(ispin), 0.0_dp, residual_vects(ispin, irv))
737 : END DO
738 : END DO
739 : !
740 4038 : CALL cp_fm_release(awork)
741 8076 : CALL cp_fm_release(vomat)
742 : END IF
743 :
744 4038 : CALL timestop(handle)
745 :
746 8076 : END SUBROUTINE tddfpt_compute_residual_vects
747 :
748 : ! **************************************************************************************************
749 : !> \brief Perform Davidson iterations.
750 : !> \param evects TDDFPT trial vectors (modified on exit)
751 : !> \param evals TDDFPT eigenvalues (modified on exit)
752 : !> \param S_evects cached matrix product S * evects (modified on exit)
753 : !> \param gs_mos molecular orbitals optimised for the ground state
754 : !> \param tddfpt_control TDDFPT control parameters
755 : !> \param matrix_ks Kohn-Sham matrix
756 : !> \param qs_env Quickstep environment
757 : !> \param kernel_env kernel environment
758 : !> \param sub_env parallel (sub)group environment
759 : !> \param logger CP2K logger
760 : !> \param iter_unit I/O unit to write basic iteration information
761 : !> \param energy_unit I/O unit to write detailed energy information
762 : !> \param tddfpt_print_section TDDFPT print input section (need to write TDDFPT restart files)
763 : !> \param work_matrices collection of work matrices (modified on exit)
764 : !> \return energy convergence achieved (in Hartree)
765 : !> \par History
766 : !> * 03.2017 code related to Davidson eigensolver has been moved here from the main subroutine
767 : !> tddfpt() [Sergey Chulkov]
768 : !> \note Based on the subroutines apply_op() and iterative_solver() originally created by
769 : !> Thomas Chassaing in 2002.
770 : ! **************************************************************************************************
771 1150 : FUNCTION tddfpt_davidson_solver(evects, evals, S_evects, gs_mos, tddfpt_control, &
772 : matrix_ks, qs_env, kernel_env, &
773 : sub_env, logger, iter_unit, energy_unit, &
774 : tddfpt_print_section, work_matrices) RESULT(conv)
775 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(inout) :: evects
776 : REAL(kind=dp), DIMENSION(:), INTENT(inout) :: evals
777 : TYPE(cp_fm_type), DIMENSION(:, :), INTENT(inout) :: S_evects
778 : TYPE(tddfpt_ground_state_mos), DIMENSION(:), &
779 : INTENT(in) :: gs_mos
780 : TYPE(tddfpt2_control_type), POINTER :: tddfpt_control
781 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks
782 : TYPE(qs_environment_type), POINTER :: qs_env
783 : TYPE(kernel_env_type), INTENT(in) :: kernel_env
784 : TYPE(tddfpt_subgroup_env_type), INTENT(in) :: sub_env
785 : TYPE(cp_logger_type), POINTER :: logger
786 : INTEGER, INTENT(in) :: iter_unit, energy_unit
787 : TYPE(section_vals_type), POINTER :: tddfpt_print_section
788 : TYPE(tddfpt_work_matrices), INTENT(inout) :: work_matrices
789 : REAL(kind=dp) :: conv
790 :
791 : CHARACTER(LEN=*), PARAMETER :: routineN = 'tddfpt_davidson_solver'
792 :
793 : INTEGER :: handle, ispin, istate, iter, &
794 : max_krylov_vects, nspins, nstates, &
795 : nstates_conv, nvects_exist, nvects_new
796 : INTEGER(kind=int_8) :: nstates_total
797 : LOGICAL :: is_nonortho
798 : REAL(kind=dp) :: t1, t2
799 1150 : REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: evals_last
800 1150 : REAL(kind=dp), DIMENSION(:, :), POINTER :: Atilde
801 1150 : TYPE(cp_fm_type), ALLOCATABLE, DIMENSION(:, :) :: Aop_krylov, Aop_ritz, krylov_vects, &
802 1150 : S_krylov
803 1150 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
804 :
805 1150 : CALL timeset(routineN, handle)
806 :
807 1150 : nspins = SIZE(gs_mos)
808 1150 : nstates = tddfpt_control%nstates
809 1150 : nstates_total = tddfpt_total_number_of_states(gs_mos)
810 :
811 : IF (debug_this_module) THEN
812 : CPASSERT(SIZE(evects, 1) == nspins)
813 : CPASSERT(SIZE(evects, 2) == nstates)
814 : CPASSERT(SIZE(evals) == nstates)
815 : END IF
816 :
817 1150 : CALL get_qs_env(qs_env, matrix_s=matrix_s)
818 :
819 : ! adjust the number of Krylov vectors
820 1150 : max_krylov_vects = tddfpt_control%nkvs
821 1150 : IF (max_krylov_vects < nstates) max_krylov_vects = nstates
822 1150 : IF (INT(max_krylov_vects, kind=int_8) > nstates_total) max_krylov_vects = INT(nstates_total)
823 :
824 11578 : ALLOCATE (Aop_ritz(nspins, nstates))
825 4450 : DO istate = 1, nstates
826 8128 : DO ispin = 1, nspins
827 6978 : CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, Aop_ritz(ispin, istate))
828 : END DO
829 : END DO
830 :
831 3450 : ALLOCATE (evals_last(max_krylov_vects))
832 : ALLOCATE (Aop_krylov(nspins, max_krylov_vects), krylov_vects(nspins, max_krylov_vects), &
833 823454 : S_krylov(nspins, max_krylov_vects))
834 :
835 4450 : DO istate = 1, nstates
836 8128 : DO ispin = 1, nspins
837 3678 : CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, krylov_vects(ispin, istate))
838 3678 : CALL cp_fm_to_fm(evects(ispin, istate), krylov_vects(ispin, istate))
839 :
840 3678 : CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, S_krylov(ispin, istate))
841 3678 : CALL cp_fm_to_fm(S_evects(ispin, istate), S_krylov(ispin, istate))
842 :
843 6978 : CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, Aop_krylov(ispin, istate))
844 : END DO
845 : END DO
846 :
847 1150 : nvects_exist = 0
848 1150 : nvects_new = nstates
849 :
850 1150 : t1 = m_walltime()
851 :
852 1150 : ALLOCATE (Atilde(1, 1))
853 :
854 5184 : DO
855 : ! davidson iteration
856 5184 : CALL cp_iterate(logger%iter_info, iter_nr_out=iter)
857 :
858 : CALL tddfpt_compute_Aop_evects(Aop_evects=Aop_krylov(:, nvects_exist + 1:nvects_exist + nvects_new), &
859 : evects=krylov_vects(:, nvects_exist + 1:nvects_exist + nvects_new), &
860 : S_evects=S_krylov(:, nvects_exist + 1:nvects_exist + nvects_new), &
861 : gs_mos=gs_mos, tddfpt_control=tddfpt_control, &
862 : matrix_ks=matrix_ks, &
863 : qs_env=qs_env, kernel_env=kernel_env, &
864 : sub_env=sub_env, &
865 : work_matrices=work_matrices, &
866 5184 : matrix_s=matrix_s(1)%matrix)
867 :
868 : CALL tddfpt_compute_ritz_vects(ritz_vects=evects, Aop_ritz=Aop_ritz, &
869 : evals=evals_last(1:nvects_exist + nvects_new), &
870 : krylov_vects=krylov_vects(:, 1:nvects_exist + nvects_new), &
871 : Aop_krylov=Aop_krylov(:, 1:nvects_exist + nvects_new), &
872 5184 : Atilde=Atilde, nkvo=nvects_exist, nkvn=nvects_new)
873 :
874 : CALL tddfpt_write_restart(evects=evects, evals=evals_last(1:nstates), gs_mos=gs_mos, &
875 5184 : logger=logger, tddfpt_print_section=tddfpt_print_section)
876 :
877 24312 : conv = MAXVAL(ABS(evals_last(1:nstates) - evals(1:nstates)))
878 :
879 5184 : nvects_exist = nvects_exist + nvects_new
880 5184 : IF (nvects_exist + nvects_new > max_krylov_vects) &
881 382 : nvects_new = max_krylov_vects - nvects_exist
882 5184 : IF (iter >= tddfpt_control%niters) nvects_new = 0
883 :
884 5184 : IF (conv > tddfpt_control%conv .AND. nvects_new > 0) THEN
885 : ! compute residual vectors for the next iteration
886 14018 : DO istate = 1, nvects_new
887 25648 : DO ispin = 1, nspins
888 : CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, &
889 11630 : krylov_vects(ispin, nvects_exist + istate))
890 : CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, &
891 11630 : S_krylov(ispin, nvects_exist + istate))
892 : CALL fm_pool_create_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, &
893 21610 : Aop_krylov(ispin, nvects_exist + istate))
894 : END DO
895 : END DO
896 :
897 : CALL tddfpt_compute_residual_vects(residual_vects=krylov_vects(:, nvects_exist + 1:nvects_exist + nvects_new), &
898 : evals=evals_last(1:nvects_new), &
899 : ritz_vects=evects(:, 1:nvects_new), Aop_ritz=Aop_ritz(:, 1:nvects_new), &
900 4038 : gs_mos=gs_mos, matrix_s=matrix_s(1)%matrix)
901 :
902 : CALL tddfpt_orthogonalize_psi1_psi0(krylov_vects(:, nvects_exist + 1:nvects_exist + nvects_new), &
903 : work_matrices%S_C0_C0T, qs_env, &
904 4038 : gs_mos, evals(1:nstates), tddfpt_control, work_matrices%S_C0)
905 :
906 : CALL tddfpt_orthonormalize_psi1_psi1(krylov_vects(:, 1:nvects_exist + nvects_new), nvects_new, &
907 4038 : S_krylov(:, 1:nvects_exist + nvects_new), matrix_s(1)%matrix)
908 :
909 : is_nonortho = tddfpt_is_nonorthogonal_psi1_psi0(krylov_vects(:, nvects_exist + 1:nvects_exist + nvects_new), &
910 4038 : work_matrices%S_C0, tddfpt_control%orthogonal_eps)
911 : ELSE
912 : ! convergence or the maximum number of Krylov vectors have been achieved
913 1146 : nvects_new = 0
914 1146 : is_nonortho = .FALSE.
915 : END IF
916 :
917 5184 : t2 = m_walltime()
918 5184 : IF (energy_unit > 0) THEN
919 314 : WRITE (energy_unit, '(/,4X,A,T14,A,T36,A)') "State", "Exc. energy (eV)", "Convergence (eV)"
920 723 : DO istate = 1, nstates
921 409 : WRITE (energy_unit, '(1X,I8,T12,F14.7,T38,ES11.4)') istate, &
922 1132 : evals_last(istate)*evolt, (evals_last(istate) - evals(istate))*evolt
923 : END DO
924 314 : WRITE (energy_unit, *)
925 314 : CALL m_flush(energy_unit)
926 : END IF
927 :
928 5184 : IF (iter_unit > 0) THEN
929 2592 : nstates_conv = 0
930 9564 : DO istate = 1, nstates
931 6972 : IF (ABS(evals_last(istate) - evals(istate)) <= tddfpt_control%conv) &
932 4918 : nstates_conv = nstates_conv + 1
933 : END DO
934 :
935 2592 : WRITE (iter_unit, '(T7,I8,T24,F7.1,T40,ES11.4,T66,I8)') iter, t2 - t1, conv, nstates_conv
936 2592 : CALL m_flush(iter_unit)
937 : END IF
938 :
939 19128 : t1 = t2
940 19128 : evals(1:nstates) = evals_last(1:nstates)
941 :
942 : ! nvects_new == 0 if iter >= tddfpt_control%niters
943 5184 : IF (nvects_new == 0 .OR. is_nonortho) THEN
944 : ! restart Davidson iterations
945 : CALL tddfpt_orthogonalize_psi1_psi0(evects, work_matrices%S_C0_C0T, qs_env, &
946 : gs_mos, &
947 1150 : evals(1:nstates), tddfpt_control, work_matrices%S_C0)
948 1150 : CALL tddfpt_orthonormalize_psi1_psi1(evects, nstates, S_evects, matrix_s(1)%matrix)
949 :
950 : EXIT
951 : END IF
952 : END DO
953 :
954 1150 : DEALLOCATE (Atilde)
955 :
956 14430 : DO istate = nvects_exist + nvects_new, 1, -1
957 29738 : DO ispin = nspins, 1, -1
958 15308 : CALL fm_pool_give_back_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, Aop_krylov(ispin, istate))
959 15308 : CALL fm_pool_give_back_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, S_krylov(ispin, istate))
960 28588 : CALL fm_pool_give_back_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, krylov_vects(ispin, istate))
961 : END DO
962 : END DO
963 1150 : DEALLOCATE (Aop_krylov, krylov_vects, S_krylov)
964 1150 : DEALLOCATE (evals_last)
965 :
966 4450 : DO istate = nstates, 1, -1
967 8128 : DO ispin = nspins, 1, -1
968 6978 : CALL fm_pool_give_back_fm(work_matrices%fm_pool_ao_mo_occ(ispin)%pool, Aop_ritz(ispin, istate))
969 : END DO
970 : END DO
971 1150 : DEALLOCATE (Aop_ritz)
972 :
973 1150 : CALL timestop(handle)
974 :
975 1150 : END FUNCTION tddfpt_davidson_solver
976 :
977 : END MODULE qs_tddfpt2_eigensolver
|