Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2026 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief module that contains the algorithms to perform an iterative
10 : !> diagonalization by the block-Davidson approach
11 : !> P. Blaha, et al J. Comp. Physics, 229, (2010), 453-460
12 : !> Iterative diagonalization in augmented plane wave based
13 : !> methods in electronic structure calculations
14 : !> \par History
15 : !> 05.2011 created [MI]
16 : !> \author MI
17 : ! **************************************************************************************************
18 : MODULE qs_scf_block_davidson
19 :
20 : USE cp_cfm_basic_linalg, ONLY: cp_cfm_column_scale,&
21 : cp_cfm_gemm,&
22 : cp_cfm_get_diag,&
23 : cp_cfm_scale_and_add,&
24 : cp_cfm_vectorsnorm
25 : USE cp_cfm_diag, ONLY: cp_cfm_geeig
26 : USE cp_cfm_types, ONLY: cp_cfm_create,&
27 : cp_cfm_get_submatrix,&
28 : cp_cfm_release,&
29 : cp_cfm_set_all,&
30 : cp_cfm_set_submatrix,&
31 : cp_cfm_to_cfm,&
32 : cp_cfm_type
33 : USE cp_dbcsr_api, ONLY: &
34 : dbcsr_add, dbcsr_copy, dbcsr_create, dbcsr_get_info, dbcsr_init_p, &
35 : dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, dbcsr_iterator_start, &
36 : dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_multiply, dbcsr_release_p, dbcsr_type, &
37 : dbcsr_type_no_symmetry, dbcsr_type_symmetric
38 : USE cp_dbcsr_contrib, ONLY: dbcsr_get_diag,&
39 : dbcsr_scale_by_vector
40 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
41 : copy_fm_to_dbcsr,&
42 : cp_dbcsr_m_by_n_from_row_template,&
43 : cp_dbcsr_m_by_n_from_template,&
44 : cp_dbcsr_sm_fm_multiply
45 : USE cp_fm_basic_linalg, ONLY: cp_fm_column_scale,&
46 : cp_fm_scale_and_add,&
47 : cp_fm_symm,&
48 : cp_fm_transpose,&
49 : cp_fm_triangular_invert,&
50 : cp_fm_uplo_to_full
51 : USE cp_fm_cholesky, ONLY: cp_fm_cholesky_decompose,&
52 : cp_fm_cholesky_restore
53 : USE cp_fm_diag, ONLY: choose_eigv_solver,&
54 : cp_fm_power
55 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
56 : cp_fm_struct_release,&
57 : cp_fm_struct_type
58 : USE cp_fm_types, ONLY: cp_fm_create,&
59 : cp_fm_get_diag,&
60 : cp_fm_release,&
61 : cp_fm_set_all,&
62 : cp_fm_to_fm,&
63 : cp_fm_to_fm_submat,&
64 : cp_fm_type,&
65 : cp_fm_vectorsnorm
66 : USE kinds, ONLY: dp
67 : USE machine, ONLY: m_walltime
68 : USE mathconstants, ONLY: z_one,&
69 : z_zero
70 : USE message_passing, ONLY: mp_comm_type
71 : USE parallel_gemm_api, ONLY: parallel_gemm
72 : USE preconditioner, ONLY: apply_preconditioner
73 : USE preconditioner_types, ONLY: preconditioner_type
74 : USE qs_block_davidson_types, ONLY: davidson_type
75 : USE qs_mo_types, ONLY: get_mo_set,&
76 : mo_set_type
77 : #include "./base/base_uses.f90"
78 :
79 : IMPLICIT NONE
80 : PRIVATE
81 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_scf_block_davidson'
82 :
83 : PUBLIC :: generate_extended_space, generate_extended_space_c, generate_extended_space_sparse
84 :
85 : CONTAINS
86 :
87 : ! **************************************************************************************************
88 : !> \brief ...
89 : !> \param bdav_env ...
90 : !> \param mo_set ...
91 : !> \param matrix_h ...
92 : !> \param matrix_s ...
93 : !> \param output_unit ...
94 : !> \param preconditioner ...
95 : ! **************************************************************************************************
96 40 : SUBROUTINE generate_extended_space(bdav_env, mo_set, matrix_h, matrix_s, output_unit, &
97 : preconditioner)
98 :
99 : TYPE(davidson_type) :: bdav_env
100 : TYPE(mo_set_type), INTENT(IN) :: mo_set
101 : TYPE(dbcsr_type), POINTER :: matrix_h, matrix_s
102 : INTEGER, INTENT(IN) :: output_unit
103 : TYPE(preconditioner_type), OPTIONAL, POINTER :: preconditioner
104 :
105 : CHARACTER(len=*), PARAMETER :: routineN = 'generate_extended_space'
106 :
107 : INTEGER :: handle, homo, i_first, i_last, imo, iter, j, jj, max_iter, n, nao, nmat, nmat2, &
108 : nmo, nmo_converged, nmo_not_converged, nset, nset_conv, nset_not_conv
109 40 : INTEGER, ALLOCATABLE, DIMENSION(:) :: iconv, inotconv
110 40 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: iconv_set, inotconv_set
111 : LOGICAL :: converged, do_apply_preconditioner
112 : REAL(dp) :: lambda, max_norm, min_norm, t1, t2
113 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: ritz_coeff, vnorm
114 40 : REAL(dp), DIMENSION(:), POINTER :: eig_not_conv, eigenvalues, evals
115 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
116 : TYPE(cp_fm_type) :: c_conv, c_notconv, c_out, h_block, h_fm, &
117 : m_hc, m_sc, m_tmp, mt_tmp, s_block, &
118 : s_fm, v_block, w_block
119 : TYPE(cp_fm_type), POINTER :: c_pz, c_z, mo_coeff
120 : TYPE(dbcsr_type), POINTER :: mo_coeff_b
121 :
122 40 : CALL timeset(routineN, handle)
123 :
124 40 : NULLIFY (mo_coeff, mo_coeff_b, eigenvalues)
125 :
126 40 : do_apply_preconditioner = .FALSE.
127 40 : IF (PRESENT(preconditioner)) do_apply_preconditioner = .TRUE.
128 : CALL get_mo_set(mo_set=mo_set, mo_coeff=mo_coeff, mo_coeff_b=mo_coeff_b, eigenvalues=eigenvalues, &
129 40 : nao=nao, nmo=nmo, homo=homo)
130 40 : IF (do_apply_preconditioner) THEN
131 36 : max_iter = bdav_env%max_iter
132 : ELSE
133 : max_iter = 1
134 : END IF
135 :
136 40 : NULLIFY (c_z, c_pz)
137 40 : NULLIFY (evals, eig_not_conv)
138 40 : t1 = m_walltime()
139 40 : IF (output_unit > 0) THEN
140 : WRITE (output_unit, "(T15,A,T23,A,T36,A,T49,A,T60,A,/,T8,A)") &
141 0 : " Cycle ", " conv. MOS ", " B2MAX ", " B2MIN ", " Time", REPEAT("-", 60)
142 : END IF
143 :
144 120 : ALLOCATE (iconv(nmo))
145 80 : ALLOCATE (inotconv(nmo))
146 120 : ALLOCATE (ritz_coeff(nmo))
147 80 : ALLOCATE (vnorm(nmo))
148 :
149 40 : converged = .FALSE.
150 124 : DO iter = 1, max_iter
151 :
152 : ! compute Ritz values
153 88 : ritz_coeff = 0.0_dp
154 88 : CALL cp_fm_create(m_hc, mo_coeff%matrix_struct, name="hc")
155 88 : CALL cp_dbcsr_sm_fm_multiply(matrix_h, mo_coeff, m_hc, nmo)
156 88 : CALL cp_fm_create(m_sc, mo_coeff%matrix_struct, name="sc")
157 88 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, mo_coeff, m_sc, nmo)
158 :
159 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmo, ncol_global=nmo, &
160 : context=mo_coeff%matrix_struct%context, &
161 88 : para_env=mo_coeff%matrix_struct%para_env)
162 88 : CALL cp_fm_create(m_tmp, fm_struct_tmp, name="matrix_tmp")
163 88 : CALL cp_fm_struct_release(fm_struct_tmp)
164 :
165 88 : CALL parallel_gemm('T', 'N', nmo, nmo, nao, 1.0_dp, mo_coeff, m_hc, 0.0_dp, m_tmp)
166 88 : CALL cp_fm_get_diag(m_tmp, ritz_coeff)
167 88 : CALL cp_fm_release(m_tmp)
168 :
169 : ! Check for converged eigenvectors
170 88 : c_z => bdav_env%matrix_z
171 88 : c_pz => bdav_env%matrix_pz
172 88 : CALL cp_fm_to_fm(m_sc, c_z)
173 88 : CALL cp_fm_column_scale(c_z, ritz_coeff)
174 88 : CALL cp_fm_scale_and_add(-1.0_dp, c_z, 1.0_dp, m_hc)
175 88 : CALL cp_fm_vectorsnorm(c_z, vnorm)
176 :
177 88 : nmo_converged = 0
178 88 : nmo_not_converged = 0
179 88 : max_norm = 0.0_dp
180 88 : min_norm = 1.e10_dp
181 3256 : DO imo = 1, nmo
182 3168 : max_norm = MAX(max_norm, vnorm(imo))
183 3256 : min_norm = MIN(min_norm, vnorm(imo))
184 : END DO
185 88 : iconv = 0
186 88 : inotconv = 0
187 3256 : DO imo = 1, nmo
188 3256 : IF (vnorm(imo) <= bdav_env%eps_iter) THEN
189 136 : nmo_converged = nmo_converged + 1
190 136 : iconv(nmo_converged) = imo
191 : ELSE
192 3032 : nmo_not_converged = nmo_not_converged + 1
193 3032 : inotconv(nmo_not_converged) = imo
194 : END IF
195 : END DO
196 :
197 88 : IF (nmo_converged > 0) THEN
198 48 : ALLOCATE (iconv_set(nmo_converged, 2))
199 48 : ALLOCATE (inotconv_set(nmo_not_converged, 2))
200 16 : i_last = iconv(1)
201 16 : nset = 0
202 152 : DO j = 1, nmo_converged
203 136 : imo = iconv(j)
204 :
205 152 : IF (imo == i_last + 1) THEN
206 102 : i_last = imo
207 102 : iconv_set(nset, 2) = imo
208 : ELSE
209 34 : i_last = imo
210 34 : nset = nset + 1
211 34 : iconv_set(nset, 1) = imo
212 34 : iconv_set(nset, 2) = imo
213 : END IF
214 : END DO
215 16 : nset_conv = nset
216 :
217 16 : i_last = inotconv(1)
218 16 : nset = 0
219 456 : DO j = 1, nmo_not_converged
220 440 : imo = inotconv(j)
221 :
222 456 : IF (imo == i_last + 1) THEN
223 398 : i_last = imo
224 398 : inotconv_set(nset, 2) = imo
225 : ELSE
226 42 : i_last = imo
227 42 : nset = nset + 1
228 42 : inotconv_set(nset, 1) = imo
229 42 : inotconv_set(nset, 2) = imo
230 : END IF
231 : END DO
232 16 : nset_not_conv = nset
233 16 : CALL cp_fm_release(m_sc)
234 16 : CALL cp_fm_release(m_hc)
235 16 : NULLIFY (c_z, c_pz)
236 : END IF
237 :
238 88 : IF (REAL(nmo_converged, dp)/REAL(nmo, dp) > bdav_env%conv_percent) THEN
239 4 : converged = .TRUE.
240 4 : DEALLOCATE (iconv_set)
241 4 : DEALLOCATE (inotconv_set)
242 4 : t2 = m_walltime()
243 4 : IF (output_unit > 0) THEN
244 : WRITE (output_unit, '(T16,I5,T24,I6,T33,E12.4,2x,E12.4,T60,F8.3)') &
245 0 : iter, nmo_converged, max_norm, min_norm, t2 - t1
246 :
247 0 : WRITE (output_unit, *) " Reached convergence in ", iter, &
248 0 : " Davidson iterations"
249 : END IF
250 :
251 : EXIT
252 : END IF
253 :
254 84 : IF (nmo_converged > 0) THEN
255 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nao, &
256 : context=mo_coeff%matrix_struct%context, &
257 12 : para_env=mo_coeff%matrix_struct%para_env)
258 : !allocate h_fm
259 12 : CALL cp_fm_create(h_fm, fm_struct_tmp, name="matrix_tmp")
260 : !allocate s_fm
261 12 : CALL cp_fm_create(s_fm, fm_struct_tmp, name="matrix_tmp")
262 : !copy matrix_h in h_fm
263 12 : CALL copy_dbcsr_to_fm(matrix_h, h_fm)
264 12 : CALL cp_fm_uplo_to_full(h_fm, s_fm)
265 :
266 : !copy matrix_s in s_fm
267 : ! CALL cp_fm_set_all(s_fm,0.0_dp)
268 12 : CALL copy_dbcsr_to_fm(matrix_s, s_fm)
269 :
270 : !allocate c_out
271 12 : CALL cp_fm_create(c_out, fm_struct_tmp, name="matrix_tmp")
272 : ! set c_out to zero
273 12 : CALL cp_fm_set_all(c_out, 0.0_dp)
274 12 : CALL cp_fm_struct_release(fm_struct_tmp)
275 :
276 : !allocate c_conv
277 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmo_converged, &
278 : context=mo_coeff%matrix_struct%context, &
279 12 : para_env=mo_coeff%matrix_struct%para_env)
280 12 : CALL cp_fm_create(c_conv, fm_struct_tmp, name="c_conv")
281 12 : CALL cp_fm_set_all(c_conv, 0.0_dp)
282 : !allocate m_tmp
283 12 : CALL cp_fm_create(m_tmp, fm_struct_tmp, name="m_tmp_nxmc")
284 12 : CALL cp_fm_struct_release(fm_struct_tmp)
285 : END IF
286 :
287 : !allocate c_notconv
288 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmo_not_converged, &
289 : context=mo_coeff%matrix_struct%context, &
290 84 : para_env=mo_coeff%matrix_struct%para_env)
291 84 : CALL cp_fm_create(c_notconv, fm_struct_tmp, name="c_notconv")
292 84 : CALL cp_fm_set_all(c_notconv, 0.0_dp)
293 84 : IF (nmo_converged > 0) THEN
294 12 : CALL cp_fm_create(m_hc, fm_struct_tmp, name="m_hc")
295 12 : CALL cp_fm_create(m_sc, fm_struct_tmp, name="m_sc")
296 : !allocate c_z
297 12 : ALLOCATE (c_z, c_pz)
298 12 : CALL cp_fm_create(c_z, fm_struct_tmp, name="c_z")
299 12 : CALL cp_fm_create(c_pz, fm_struct_tmp, name="c_pz")
300 12 : CALL cp_fm_set_all(c_z, 0.0_dp)
301 :
302 : ! sum contributions to c_out
303 12 : jj = 1
304 34 : DO j = 1, nset_conv
305 22 : i_first = iconv_set(j, 1)
306 22 : i_last = iconv_set(j, 2)
307 22 : n = i_last - i_first + 1
308 22 : CALL cp_fm_to_fm_submat(mo_coeff, c_conv, nao, n, 1, i_first, 1, jj)
309 34 : jj = jj + n
310 : END DO
311 12 : CALL cp_fm_symm('L', 'U', nao, nmo_converged, 1.0_dp, s_fm, c_conv, 0.0_dp, m_tmp)
312 12 : CALL parallel_gemm('N', 'T', nao, nao, nmo_converged, 1.0_dp, m_tmp, m_tmp, 0.0_dp, c_out)
313 :
314 : ! project c_out out of H
315 12 : lambda = 100.0_dp*ABS(eigenvalues(homo))
316 12 : CALL cp_fm_scale_and_add(lambda, c_out, 1.0_dp, h_fm)
317 12 : CALL cp_fm_release(m_tmp)
318 12 : CALL cp_fm_release(h_fm)
319 :
320 : END IF
321 :
322 : !allocate m_tmp
323 84 : CALL cp_fm_create(m_tmp, fm_struct_tmp, name="m_tmp_nxm")
324 84 : CALL cp_fm_struct_release(fm_struct_tmp)
325 84 : IF (nmo_converged > 0) THEN
326 36 : ALLOCATE (eig_not_conv(nmo_not_converged))
327 12 : jj = 1
328 42 : DO j = 1, nset_not_conv
329 30 : i_first = inotconv_set(j, 1)
330 30 : i_last = inotconv_set(j, 2)
331 30 : n = i_last - i_first + 1
332 30 : CALL cp_fm_to_fm_submat(mo_coeff, c_notconv, nao, n, 1, i_first, 1, jj)
333 404 : eig_not_conv(jj:jj + n - 1) = ritz_coeff(i_first:i_last)
334 42 : jj = jj + n
335 : END DO
336 12 : CALL parallel_gemm('N', 'N', nao, nmo_not_converged, nao, 1.0_dp, c_out, c_notconv, 0.0_dp, m_hc)
337 12 : CALL cp_fm_symm('L', 'U', nao, nmo_not_converged, 1.0_dp, s_fm, c_notconv, 0.0_dp, m_sc)
338 : ! extend suspace using only the not converged vectors
339 12 : CALL cp_fm_to_fm(m_sc, m_tmp)
340 12 : CALL cp_fm_column_scale(m_tmp, eig_not_conv)
341 12 : CALL cp_fm_scale_and_add(-1.0_dp, m_tmp, 1.0_dp, m_hc)
342 12 : DEALLOCATE (eig_not_conv)
343 12 : CALL cp_fm_to_fm(m_tmp, c_z)
344 : ELSE
345 72 : CALL cp_fm_to_fm(mo_coeff, c_notconv)
346 : END IF
347 :
348 : !preconditioner
349 84 : IF (do_apply_preconditioner) THEN
350 80 : IF (preconditioner%in_use /= 0) THEN
351 80 : CALL apply_preconditioner(preconditioner, c_z, c_pz)
352 : ELSE
353 0 : CALL cp_fm_to_fm(c_z, c_pz)
354 : END IF
355 : ELSE
356 4 : CALL cp_fm_to_fm(c_z, c_pz)
357 : END IF
358 84 : CALL cp_fm_release(m_tmp)
359 :
360 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmo_not_converged, ncol_global=nmo_not_converged, &
361 : context=mo_coeff%matrix_struct%context, &
362 84 : para_env=mo_coeff%matrix_struct%para_env)
363 :
364 84 : CALL cp_fm_create(m_tmp, fm_struct_tmp, name="m_tmp_mxm")
365 84 : CALL cp_fm_create(mt_tmp, fm_struct_tmp, name="mt_tmp_mxm")
366 84 : CALL cp_fm_struct_release(fm_struct_tmp)
367 :
368 84 : nmat = nmo_not_converged
369 84 : nmat2 = 2*nmo_not_converged
370 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmat2, ncol_global=nmat2, &
371 : context=mo_coeff%matrix_struct%context, &
372 84 : para_env=mo_coeff%matrix_struct%para_env)
373 :
374 84 : CALL cp_fm_create(s_block, fm_struct_tmp, name="sb")
375 84 : CALL cp_fm_create(h_block, fm_struct_tmp, name="hb")
376 84 : CALL cp_fm_create(v_block, fm_struct_tmp, name="vb")
377 84 : CALL cp_fm_create(w_block, fm_struct_tmp, name="wb")
378 252 : ALLOCATE (evals(nmat2))
379 :
380 84 : CALL cp_fm_struct_release(fm_struct_tmp)
381 :
382 : ! compute CSC
383 84 : CALL cp_fm_set_all(s_block, 0.0_dp, 1.0_dp)
384 :
385 : ! compute CHC
386 84 : CALL parallel_gemm('T', 'N', nmat, nmat, nao, 1.0_dp, c_notconv, m_hc, 0.0_dp, m_tmp)
387 84 : CALL cp_fm_to_fm_submat(m_tmp, h_block, nmat, nmat, 1, 1, 1, 1)
388 :
389 : ! compute ZSC
390 84 : CALL parallel_gemm('T', 'N', nmat, nmat, nao, 1.0_dp, c_pz, m_sc, 0.0_dp, m_tmp)
391 84 : CALL cp_fm_to_fm_submat(m_tmp, s_block, nmat, nmat, 1, 1, 1 + nmat, 1)
392 84 : CALL cp_fm_transpose(m_tmp, mt_tmp)
393 84 : CALL cp_fm_to_fm_submat(mt_tmp, s_block, nmat, nmat, 1, 1, 1, 1 + nmat)
394 : ! compute ZHC
395 84 : CALL parallel_gemm('T', 'N', nmat, nmat, nao, 1.0_dp, c_pz, m_hc, 0.0_dp, m_tmp)
396 84 : CALL cp_fm_to_fm_submat(m_tmp, h_block, nmat, nmat, 1, 1, 1 + nmat, 1)
397 84 : CALL cp_fm_transpose(m_tmp, mt_tmp)
398 84 : CALL cp_fm_to_fm_submat(mt_tmp, h_block, nmat, nmat, 1, 1, 1, 1 + nmat)
399 :
400 84 : CALL cp_fm_release(mt_tmp)
401 :
402 : ! reuse m_sc and m_hc to computr HZ and SZ
403 84 : IF (nmo_converged > 0) THEN
404 12 : CALL parallel_gemm('N', 'N', nao, nmat, nao, 1.0_dp, c_out, c_pz, 0.0_dp, m_hc)
405 12 : CALL cp_fm_symm('L', 'U', nao, nmo_not_converged, 1.0_dp, s_fm, c_pz, 0.0_dp, m_sc)
406 :
407 12 : CALL cp_fm_release(c_out)
408 12 : CALL cp_fm_release(c_conv)
409 12 : CALL cp_fm_release(s_fm)
410 : ELSE
411 72 : CALL cp_dbcsr_sm_fm_multiply(matrix_h, c_pz, m_hc, nmo)
412 72 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, c_pz, m_sc, nmo)
413 : END IF
414 :
415 : ! compute ZSZ
416 84 : CALL parallel_gemm('T', 'N', nmat, nmat, nao, 1.0_dp, c_pz, m_sc, 0.0_dp, m_tmp)
417 84 : CALL cp_fm_to_fm_submat(m_tmp, s_block, nmat, nmat, 1, 1, 1 + nmat, 1 + nmat)
418 : ! compute ZHZ
419 84 : CALL parallel_gemm('T', 'N', nmat, nmat, nao, 1.0_dp, c_pz, m_hc, 0.0_dp, m_tmp)
420 84 : CALL cp_fm_to_fm_submat(m_tmp, h_block, nmat, nmat, 1, 1, 1 + nmat, 1 + nmat)
421 :
422 84 : CALL cp_fm_release(m_sc)
423 :
424 : ! solution of the reduced eigenvalues problem
425 84 : CALL reduce_extended_space(s_block, h_block, v_block, w_block, evals, nmat2)
426 :
427 : ! extract egenvectors
428 84 : CALL cp_fm_to_fm_submat(v_block, m_tmp, nmat, nmat, 1, 1, 1, 1)
429 84 : CALL parallel_gemm('N', 'N', nao, nmat, nmat, 1.0_dp, c_notconv, m_tmp, 0.0_dp, m_hc)
430 84 : CALL cp_fm_to_fm_submat(v_block, m_tmp, nmat, nmat, 1 + nmat, 1, 1, 1)
431 84 : CALL parallel_gemm('N', 'N', nao, nmat, nmat, 1.0_dp, c_pz, m_tmp, 1.0_dp, m_hc)
432 :
433 84 : CALL cp_fm_release(m_tmp)
434 :
435 84 : CALL cp_fm_release(c_notconv)
436 84 : CALL cp_fm_release(s_block)
437 84 : CALL cp_fm_release(h_block)
438 84 : CALL cp_fm_release(w_block)
439 84 : CALL cp_fm_release(v_block)
440 :
441 84 : IF (nmo_converged > 0) THEN
442 12 : CALL cp_fm_release(c_z)
443 12 : CALL cp_fm_release(c_pz)
444 12 : DEALLOCATE (c_z, c_pz)
445 12 : jj = 1
446 42 : DO j = 1, nset_not_conv
447 30 : i_first = inotconv_set(j, 1)
448 30 : i_last = inotconv_set(j, 2)
449 30 : n = i_last - i_first + 1
450 30 : CALL cp_fm_to_fm_submat(m_hc, mo_coeff, nao, n, 1, jj, 1, i_first)
451 808 : eigenvalues(i_first:i_last) = evals(jj:jj + n - 1)
452 42 : jj = jj + n
453 : END DO
454 12 : DEALLOCATE (iconv_set)
455 12 : DEALLOCATE (inotconv_set)
456 : ELSE
457 72 : CALL cp_fm_to_fm(m_hc, mo_coeff)
458 5328 : eigenvalues(1:nmo) = evals(1:nmo)
459 : END IF
460 84 : DEALLOCATE (evals)
461 :
462 84 : CALL cp_fm_release(m_hc)
463 :
464 84 : CALL copy_fm_to_dbcsr(mo_coeff, mo_coeff_b) !fm->dbcsr
465 :
466 84 : t2 = m_walltime()
467 84 : IF (output_unit > 0) THEN
468 : WRITE (output_unit, '(T16,I5,T24,I6,T33,E12.4,2x,E12.4,T60,F8.3)') &
469 0 : iter, nmo_converged, max_norm, min_norm, t2 - t1
470 : END IF
471 720 : t1 = m_walltime()
472 :
473 : END DO ! iter
474 :
475 40 : DEALLOCATE (iconv)
476 40 : DEALLOCATE (inotconv)
477 40 : DEALLOCATE (ritz_coeff)
478 40 : DEALLOCATE (vnorm)
479 :
480 40 : CALL timestop(handle)
481 120 : END SUBROUTINE generate_extended_space
482 :
483 : ! **************************************************************************************************
484 : !> \brief iterative diagonalization by the block-Davidson approach for one
485 : !> complex K point; complex counterpart of generate_extended_space
486 : !> \param bdav_env Davidson settings of this channel
487 : !> \param mos MO pair of this K point: mos(1) real part, mos(2) imaginary part
488 : !> \param matrix_h complex Kohn-Sham matrix H(k) in full storage
489 : !> \param matrix_s complex overlap matrix S(k) in full storage
490 : !> \param output_unit unit for the Davidson iteration log
491 : !> \param eps_iter convergence threshold for the residual norm of the occupied
492 : !> MOS of this step
493 : !> \param eps_iter_empty threshold for the unoccupied MOS, identical to
494 : !> eps_iter unless the driver relaxed it with EPS_ADAPT
495 : !> \param preconditioner complex K-point preconditioner
496 : !> \note K-point MOs have no sparse dbcsr copy (mo_coeff_b). This routine does
497 : !> not update mo_coeff_b.
498 : ! **************************************************************************************************
499 1906 : SUBROUTINE generate_extended_space_c(bdav_env, mos, matrix_h, matrix_s, output_unit, &
500 : eps_iter, eps_iter_empty, preconditioner)
501 :
502 : TYPE(davidson_type) :: bdav_env
503 : TYPE(mo_set_type), INTENT(INOUT) :: mos
504 : TYPE(cp_cfm_type), INTENT(IN) :: matrix_h, matrix_s
505 : INTEGER, INTENT(IN) :: output_unit
506 : REAL(KIND=dp), INTENT(IN) :: eps_iter, eps_iter_empty
507 : TYPE(preconditioner_type), OPTIONAL, POINTER :: preconditioner
508 :
509 : CHARACTER(len=*), PARAMETER :: routineN = 'generate_extended_space_c'
510 : REAL(KIND=dp), PARAMETER :: eps_exhaust = 1.0E-12_dp, &
511 : occ_tol = 1.0E-3_dp
512 :
513 : COMPLEX(KIND=dp) :: lambda_c
514 1906 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:) :: cdiag, scaling
515 1906 : COMPLEX(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: colbuf, submat_buffer
516 : INTEGER :: handle, homo, i_first, i_last, imo, iter, j, jj, max_iter, n, nao, ncol_z, nmat, &
517 : nmat2, nmo, nmo_converged, nmo_not_converged, nset, nset_conv, nset_not_conv
518 1906 : INTEGER, ALLOCATABLE, DIMENSION(:) :: iconv, inotconv
519 1906 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: iconv_set, inotconv_set
520 : LOGICAL :: converged, do_apply_preconditioner, &
521 : exhausted
522 : REAL(KIND=dp) :: eps_iter_col, lambda, max_norm, &
523 : min_norm, t1, t2
524 1906 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: ritz_coeff, vnorm, vnorm_pz
525 1906 : REAL(KIND=dp), DIMENSION(:), POINTER :: eig_not_conv, eigenvalues, evals, &
526 1906 : occupation
527 : TYPE(cp_cfm_type) :: c_conv, c_mz, c_new, c_notconv, c_out, &
528 : c_pzo, c_pzw, c_z, h_block, h_fm, &
529 : m_hc, m_sc, m_tmp, s_block, v_block, &
530 : w_block
531 : TYPE(cp_cfm_type), POINTER :: cmo
532 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
533 :
534 : ! an occupation below this carries no weight in the density (it sits
535 : ! beyond the thermal smearing tail) and may converge at the relaxed
536 : ! empty threshold
537 :
538 : ! empirical floor for declaring a correction vector numerically zero: the
539 : ! vectors are normalized to one, double-precision roundoff sits near 1e-16,
540 : ! and the threshold errs towards bailing out early (the fallback is an
541 : ! exact diagonalization). Not taken from any reference implementation.
542 :
543 1906 : CALL timeset(routineN, handle)
544 :
545 1906 : NULLIFY (eigenvalues, evals, eig_not_conv, cmo, occupation, fm_struct_tmp)
546 :
547 1906 : do_apply_preconditioner = .FALSE.
548 1906 : IF (PRESENT(preconditioner)) do_apply_preconditioner = .TRUE.
549 : CALL get_mo_set(mo_set=mos, cmo_coeff=cmo, eigenvalues=eigenvalues, &
550 1906 : occupation_numbers=occupation, nao=nao, nmo=nmo, homo=homo)
551 1906 : IF (do_apply_preconditioner) THEN
552 1778 : max_iter = bdav_env%max_iter
553 : ELSE
554 : max_iter = 1
555 : END IF
556 :
557 1906 : t1 = m_walltime()
558 1906 : IF (output_unit > 0) THEN
559 : WRITE (output_unit, "(T15,A,T23,A,T36,A,T49,A,T60,A,/,T8,A)") &
560 0 : " Cycle ", " conv. MOS ", " B2MAX ", " B2MIN ", " Time", REPEAT("-", 60)
561 : END IF
562 :
563 5718 : ALLOCATE (iconv(nmo))
564 3812 : ALLOCATE (inotconv(nmo))
565 5718 : ALLOCATE (ritz_coeff(nmo))
566 3812 : ALLOCATE (vnorm(nmo))
567 5718 : ALLOCATE (cdiag(nmo))
568 :
569 1906 : converged = .FALSE.
570 1906 : exhausted = .FALSE.
571 14353 : DO iter = 1, max_iter
572 :
573 : ! compute Ritz values
574 13875 : ritz_coeff = 0.0_dp
575 13875 : CALL cp_cfm_create(m_hc, cmo%matrix_struct, name="hc")
576 13875 : CALL cp_cfm_gemm('N', 'N', nao, nmo, nao, z_one, matrix_h, cmo, z_zero, m_hc)
577 13875 : CALL cp_cfm_create(m_sc, cmo%matrix_struct, name="sc")
578 13875 : CALL cp_cfm_gemm('N', 'N', nao, nmo, nao, z_one, matrix_s, cmo, z_zero, m_sc)
579 :
580 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmo, ncol_global=nmo, &
581 : context=cmo%matrix_struct%context, &
582 13875 : para_env=cmo%matrix_struct%para_env)
583 13875 : CALL cp_cfm_create(m_tmp, fm_struct_tmp, name="matrix_tmp")
584 13875 : CALL cp_fm_struct_release(fm_struct_tmp)
585 :
586 13875 : CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, cmo, m_hc, z_zero, m_tmp)
587 13875 : CALL cp_cfm_get_diag(m_tmp, cdiag)
588 215406 : ritz_coeff(1:nmo) = REAL(cdiag(1:nmo), KIND=dp)
589 13875 : CALL cp_cfm_release(m_tmp)
590 :
591 : ! Check for converged eigenvectors: residual C_z = S*C*diag(ritz) - H*C
592 13875 : CALL cp_cfm_create(c_z, cmo%matrix_struct, name="z")
593 13875 : CALL cp_cfm_to_cfm(m_sc, c_z)
594 13875 : IF (ALLOCATED(scaling)) DEALLOCATE (scaling)
595 27750 : ALLOCATE (scaling(nmo))
596 215406 : scaling(:) = CMPLX(ritz_coeff, 0.0_dp, KIND=dp)
597 13875 : CALL cp_cfm_column_scale(c_z, scaling)
598 13875 : CALL cp_cfm_scale_and_add(-z_one, c_z, z_one, m_hc)
599 13875 : CALL cp_cfm_vectorsnorm(c_z, vnorm)
600 :
601 13875 : nmo_converged = 0
602 13875 : nmo_not_converged = 0
603 13875 : max_norm = 0.0_dp
604 13875 : min_norm = 1.e10_dp
605 215406 : DO imo = 1, nmo
606 201531 : max_norm = MAX(max_norm, vnorm(imo))
607 215406 : min_norm = MIN(min_norm, vnorm(imo))
608 : END DO
609 13875 : iconv = 0
610 13875 : inotconv = 0
611 215406 : DO imo = 1, nmo
612 : ! the relaxed threshold applies to the UNOCCUPIED manifold only:
613 : ! under smearing the MOS above the HOMO can still carry weight and
614 : ! leak their residual into the density, so the occupation decides,
615 : ! not the HOMO index
616 201531 : IF (occupation(imo) < occ_tol) THEN
617 126420 : eps_iter_col = eps_iter_empty
618 : ELSE
619 75111 : eps_iter_col = eps_iter
620 : END IF
621 215406 : IF (vnorm(imo) <= eps_iter_col) THEN
622 4690 : nmo_converged = nmo_converged + 1
623 4690 : iconv(nmo_converged) = imo
624 : ELSE
625 196841 : nmo_not_converged = nmo_not_converged + 1
626 196841 : inotconv(nmo_not_converged) = imo
627 : END IF
628 : END DO
629 :
630 : ! the iter > 1 gate below blocks the exit when EVERY column passes
631 : ! the entering check at iter == 1. With no unconverged column there
632 : ! is no correction to rotate with. The reduced problem further down
633 : ! would be zero-dimensional, and this head's nmo-wide residual
634 : ! matrices would be released for nothing by the packing block below.
635 : ! Reclassify all columns as unconverged so the call still performs
636 : ! the required one Rayleigh-Ritz rotation under the current
637 : ! operator: the zero-converged branch reuses the head matrices
638 : ! directly. At iter > 1 the same situation exits legitimately above,
639 : ! hence the iter guard
640 13875 : IF (iter == 1 .AND. nmo_not_converged == 0) THEN
641 244 : nmo_not_converged = nmo
642 244 : nmo_converged = 0
643 244 : iconv = 0
644 492 : DO imo = 1, nmo
645 492 : inotconv(imo) = imo
646 : END DO
647 : END IF
648 :
649 13875 : IF (nmo_converged > 0) THEN
650 5292 : ALLOCATE (iconv_set(nmo_converged, 2))
651 4040 : ALLOCATE (inotconv_set(nmo_not_converged, 2))
652 1764 : i_last = iconv(1)
653 1764 : nset = 0
654 6206 : DO j = 1, nmo_converged
655 4442 : imo = iconv(j)
656 :
657 6206 : IF (imo == i_last + 1) THEN
658 2008 : i_last = imo
659 2008 : iconv_set(nset, 2) = imo
660 : ELSE
661 2434 : i_last = imo
662 2434 : nset = nset + 1
663 2434 : iconv_set(nset, 1) = imo
664 2434 : iconv_set(nset, 2) = imo
665 : END IF
666 : END DO
667 1764 : nset_conv = nset
668 :
669 1764 : i_last = inotconv(1)
670 1764 : nset = 0
671 7858 : DO j = 1, nmo_not_converged
672 6094 : imo = inotconv(j)
673 :
674 7858 : IF (imo == i_last + 1) THEN
675 4900 : i_last = imo
676 4900 : inotconv_set(nset, 2) = imo
677 : ELSE
678 1194 : i_last = imo
679 1194 : nset = nset + 1
680 1194 : inotconv_set(nset, 1) = imo
681 1194 : inotconv_set(nset, 2) = imo
682 : END IF
683 : END DO
684 1764 : nset_not_conv = nset
685 1764 : CALL cp_cfm_release(m_sc)
686 1764 : CALL cp_cfm_release(m_hc)
687 1764 : CALL cp_cfm_release(c_z)
688 : END IF
689 :
690 : ! the convergence check runs at the head of a cycle and probes the
691 : ! ENTERING MOS. Requiring iter > 1 enforces one Rayleigh-Ritz rotation
692 : ! under the current operator per call. Exiting on the entry check
693 : ! alone would return the MOS unchanged, the density unchanged, and an
694 : ! outer SCF convergence measure of exactly zero. The SCF then stops
695 : ! at whatever the previous step left, which masquerades as
696 : ! convergence whenever the threshold is looser than the entering
697 : ! residual
698 13875 : IF (iter > 1 .AND. REAL(nmo_converged, dp)/REAL(nmo, dp) > bdav_env%conv_percent) THEN
699 1280 : converged = .TRUE.
700 1280 : DEALLOCATE (iconv_set)
701 1280 : DEALLOCATE (inotconv_set)
702 1280 : t2 = m_walltime()
703 1280 : IF (output_unit > 0) THEN
704 : WRITE (output_unit, '(T16,I5,T24,I6,T33,E12.4,2x,E12.4,T60,F8.3)') &
705 0 : iter, nmo_converged, max_norm, min_norm, t2 - t1
706 :
707 0 : WRITE (output_unit, *) " Reached convergence in ", iter, &
708 0 : " Davidson iterations"
709 : END IF
710 :
711 : EXIT
712 : END IF
713 :
714 12595 : ncol_z = nmo_not_converged
715 :
716 12595 : IF (nmo_converged > 0) THEN
717 : ! dense copy of H, shifted below by the projector onto the converged space
718 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nao, &
719 : context=cmo%matrix_struct%context, &
720 484 : para_env=cmo%matrix_struct%para_env)
721 484 : CALL cp_cfm_create(h_fm, fm_struct_tmp, name="hf")
722 484 : CALL cp_cfm_create(c_out, fm_struct_tmp, name="cout")
723 484 : CALL cp_fm_struct_release(fm_struct_tmp)
724 484 : CALL cp_cfm_to_cfm(matrix_h, h_fm)
725 :
726 : ! projector P = (S*C_conv)*(S*C_conv)^H
727 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmo_converged, &
728 : context=cmo%matrix_struct%context, &
729 484 : para_env=cmo%matrix_struct%para_env)
730 484 : CALL cp_cfm_create(c_conv, fm_struct_tmp, name="cconv")
731 484 : CALL cp_cfm_create(m_tmp, fm_struct_tmp, name="scconv")
732 484 : CALL cp_fm_struct_release(fm_struct_tmp)
733 484 : jj = 1
734 1618 : DO j = 1, nset_conv
735 1134 : i_first = iconv_set(j, 1)
736 1134 : i_last = iconv_set(j, 2)
737 1134 : n = i_last - i_first + 1
738 4536 : ALLOCATE (submat_buffer(nao, n))
739 : CALL cp_cfm_get_submatrix(cmo, submat_buffer, start_row=1, start_col=i_first, &
740 1134 : n_rows=nao, n_cols=n)
741 1134 : CALL cp_cfm_set_submatrix(c_conv, submat_buffer, start_row=1, start_col=jj)
742 1134 : DEALLOCATE (submat_buffer)
743 1618 : jj = jj + n
744 : END DO
745 : CALL cp_cfm_gemm('N', 'N', nao, nmo_converged, nao, z_one, matrix_s, c_conv, &
746 484 : z_zero, m_tmp)
747 484 : CALL cp_cfm_gemm('N', 'C', nao, nao, nmo_converged, z_one, m_tmp, m_tmp, z_zero, c_out)
748 484 : CALL cp_cfm_release(m_tmp)
749 484 : CALL cp_cfm_release(c_conv)
750 :
751 : ! project c_out out of H
752 484 : lambda = 100.0_dp*ABS(eigenvalues(homo))
753 484 : lambda_c = CMPLX(lambda, 0.0_dp, KIND=dp)
754 484 : CALL cp_cfm_scale_and_add(z_one, h_fm, lambda_c, c_out)
755 : END IF
756 :
757 : ! gather the not converged MOs
758 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=ncol_z, &
759 : context=cmo%matrix_struct%context, &
760 12595 : para_env=cmo%matrix_struct%para_env)
761 12595 : CALL cp_cfm_create(c_notconv, fm_struct_tmp, name="c_notconv")
762 12595 : CALL cp_fm_struct_release(fm_struct_tmp)
763 :
764 12595 : IF (nmo_converged > 0) THEN
765 : ! m_hc/m_sc/c_z are recreated with the ncol_z column count
766 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=ncol_z, &
767 : context=cmo%matrix_struct%context, &
768 484 : para_env=cmo%matrix_struct%para_env)
769 484 : CALL cp_cfm_create(m_hc, fm_struct_tmp, name="m_hc")
770 484 : CALL cp_cfm_create(m_sc, fm_struct_tmp, name="m_sc")
771 484 : CALL cp_cfm_create(c_z, fm_struct_tmp, name="c_z")
772 484 : CALL cp_fm_struct_release(fm_struct_tmp)
773 :
774 1452 : ALLOCATE (eig_not_conv(ncol_z))
775 484 : jj = 1
776 1634 : DO j = 1, nset_not_conv
777 1150 : i_first = inotconv_set(j, 1)
778 1150 : i_last = inotconv_set(j, 2)
779 1150 : n = i_last - i_first + 1
780 4600 : ALLOCATE (submat_buffer(nao, n))
781 : CALL cp_cfm_get_submatrix(cmo, submat_buffer, start_row=1, start_col=i_first, &
782 1150 : n_rows=nao, n_cols=n)
783 1150 : CALL cp_cfm_set_submatrix(c_notconv, submat_buffer, start_row=1, start_col=jj)
784 1150 : DEALLOCATE (submat_buffer)
785 7172 : eig_not_conv(jj:jj + n - 1) = ritz_coeff(i_first:i_last)
786 1634 : jj = jj + n
787 : END DO
788 : ! extend the subspace using only the not converged vectors
789 484 : CALL cp_cfm_gemm('N', 'N', nao, ncol_z, nao, z_one, h_fm, c_notconv, z_zero, m_hc)
790 484 : CALL cp_cfm_gemm('N', 'N', nao, ncol_z, nao, z_one, matrix_s, c_notconv, z_zero, m_sc)
791 484 : CALL cp_cfm_to_cfm(m_sc, c_z)
792 484 : IF (ALLOCATED(scaling)) DEALLOCATE (scaling)
793 1452 : ALLOCATE (scaling(ncol_z))
794 6506 : scaling(:) = CMPLX(eig_not_conv, 0.0_dp, KIND=dp)
795 484 : CALL cp_cfm_column_scale(c_z, scaling)
796 484 : CALL cp_cfm_scale_and_add(-z_one, c_z, z_one, m_hc)
797 968 : DEALLOCATE (eig_not_conv)
798 : ! h_fm is the shifted operator H+lambda*P, still needed for the HZ block below
799 : ELSE
800 : ! nothing frozen: c_notconv is the full set and the m_hc/m_sc/c_z matrices
801 : ! of the Ritz step above (nmo-wide) are reused directly
802 12111 : CALL cp_cfm_to_cfm(cmo, c_notconv)
803 : END IF
804 :
805 : ! preconditioner
806 12595 : CALL cp_cfm_create(c_mz, c_z%matrix_struct, name="pz")
807 12595 : IF (do_apply_preconditioner) THEN
808 12467 : IF (preconditioner%in_use /= 0) THEN
809 12467 : IF (nmo_converged == 0) THEN
810 : ! every column is unconverged, so the residual set already is
811 : ! the nmo-wide input the applier contract requires: apply
812 : ! directly, no scattering
813 11983 : CALL apply_preconditioner(preconditioner, c_z, c_mz)
814 : ELSE
815 : ! the complex applier works column-wise in the MO basis of
816 : ! the preconditioner construction, so the unconverged
817 : ! residuals are scattered into an nmo-wide zero buffer and
818 : ! gathered back. The unconverged columns move per contiguous
819 : ! segment of inotconv_set. The submatrix transfers end in a
820 : ! collective reduction over the matrix group, and a
821 : ! column-at-a-time loop would launch one per unconverged MO
822 484 : CALL cp_cfm_create(c_pzw, cmo%matrix_struct, name="pzw")
823 484 : CALL cp_cfm_create(c_pzo, cmo%matrix_struct, name="pzo")
824 484 : CALL cp_cfm_set_all(c_pzw, z_zero, z_zero)
825 1936 : ALLOCATE (colbuf(nao, ncol_z))
826 484 : jj = 1
827 1634 : DO j = 1, nset_not_conv
828 1150 : i_first = inotconv_set(j, 1)
829 1150 : i_last = inotconv_set(j, 2)
830 1150 : n = i_last - i_first + 1
831 1150 : CALL cp_cfm_get_submatrix(c_z, colbuf(:, 1:n), n_rows=nao, n_cols=n, start_col=jj)
832 : CALL cp_cfm_set_submatrix(c_pzw, colbuf(:, 1:n), n_rows=nao, n_cols=n, &
833 1150 : start_col=i_first)
834 1634 : jj = jj + n
835 : END DO
836 484 : CALL apply_preconditioner(preconditioner, c_pzw, c_pzo)
837 484 : jj = 1
838 1634 : DO j = 1, nset_not_conv
839 1150 : i_first = inotconv_set(j, 1)
840 1150 : i_last = inotconv_set(j, 2)
841 1150 : n = i_last - i_first + 1
842 : CALL cp_cfm_get_submatrix(c_pzo, colbuf(:, 1:n), n_rows=nao, n_cols=n, &
843 1150 : start_col=i_first)
844 1150 : CALL cp_cfm_set_submatrix(c_mz, colbuf(:, 1:n), n_rows=nao, n_cols=n, start_col=jj)
845 1634 : jj = jj + n
846 : END DO
847 484 : DEALLOCATE (colbuf)
848 484 : CALL cp_cfm_release(c_pzw)
849 968 : CALL cp_cfm_release(c_pzo)
850 : END IF
851 : ELSE
852 0 : CALL cp_cfm_to_cfm(c_z, c_mz)
853 : END IF
854 : ELSE
855 128 : CALL cp_cfm_to_cfm(c_z, c_mz)
856 : END IF
857 :
858 : ! normalize the correction vectors, then remove their components inside
859 : ! the span of the current MOS, z <- z - C*(C^H*S*z): the blocked Davidson
860 : ! subspace expansion of Kresse and Furthmueller (1996). This keeps the
861 : ! reduced S block well conditioned when a MOS is already (nearly) an
862 : ! eigenvector and its preconditioned residual is (nearly) parallel to it.
863 : ! Exhaustion: either the preconditioned correction itself, or its
864 : ! component outside the MOS span, can vanish by symmetry (the density
865 : ! keeps the little-group symmetry of the kpoint), which would make the
866 : ! reduced overlap block singular. Stop the iteration and finish the
867 : ! channel by the direct diagonalization below. The scratch of the
868 : ! interrupted iteration is released at the single cleanup point after
869 : ! the loop.
870 37785 : ALLOCATE (vnorm_pz(ncol_z))
871 12595 : CALL cp_cfm_vectorsnorm(c_mz, vnorm_pz)
872 209612 : IF (ANY(vnorm_pz < eps_exhaust)) THEN
873 : exhausted = .TRUE.
874 : ELSE
875 12595 : IF (ALLOCATED(scaling)) DEALLOCATE (scaling)
876 37785 : ALLOCATE (scaling(ncol_z))
877 209612 : scaling(:) = CMPLX(1.0_dp/vnorm_pz, 0.0_dp, KIND=dp)
878 12595 : CALL cp_cfm_column_scale(c_mz, scaling)
879 :
880 : ! projection coefficients C^H*S*z. c_z is reused as scratch for S*z
881 12595 : CALL cp_cfm_gemm('N', 'N', nao, ncol_z, nao, z_one, matrix_s, c_mz, z_zero, c_z)
882 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmo, ncol_global=ncol_z, &
883 : context=cmo%matrix_struct%context, &
884 12595 : para_env=cmo%matrix_struct%para_env)
885 12595 : CALL cp_cfm_create(m_tmp, fm_struct_tmp, name="proj_coef")
886 12595 : CALL cp_fm_struct_release(fm_struct_tmp)
887 12595 : CALL cp_cfm_gemm('C', 'N', nmo, ncol_z, nao, z_one, cmo, c_z, z_zero, m_tmp)
888 12595 : CALL cp_cfm_gemm('N', 'N', nao, ncol_z, nmo, -z_one, cmo, m_tmp, z_one, c_mz)
889 12595 : CALL cp_cfm_release(m_tmp)
890 :
891 12595 : CALL cp_cfm_vectorsnorm(c_mz, vnorm_pz)
892 221911 : IF (ANY(vnorm_pz < eps_exhaust)) THEN
893 : exhausted = .TRUE.
894 : ELSE
895 12447 : IF (ALLOCATED(scaling)) DEALLOCATE (scaling)
896 24894 : ALLOCATE (scaling(ncol_z))
897 209168 : scaling(:) = CMPLX(1.0_dp/vnorm_pz, 0.0_dp, KIND=dp)
898 12447 : CALL cp_cfm_column_scale(c_mz, scaling)
899 : END IF
900 : END IF
901 12595 : DEALLOCATE (vnorm_pz)
902 12595 : IF (exhausted) EXIT
903 :
904 12447 : nmat = ncol_z
905 12447 : nmat2 = 2*ncol_z
906 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmat2, ncol_global=nmat2, &
907 : context=cmo%matrix_struct%context, &
908 12447 : para_env=cmo%matrix_struct%para_env)
909 :
910 12447 : CALL cp_cfm_create(s_block, fm_struct_tmp, name="sb")
911 12447 : CALL cp_cfm_create(h_block, fm_struct_tmp, name="hb")
912 12447 : CALL cp_cfm_create(v_block, fm_struct_tmp, name="vb")
913 12447 : CALL cp_cfm_create(w_block, fm_struct_tmp, name="wb")
914 37341 : ALLOCATE (evals(nmat2))
915 12447 : CALL cp_fm_struct_release(fm_struct_tmp)
916 :
917 : ! compute CHC and CSC first, with m_hc/m_sc still holding the
918 : ! H*C_nc and S*C_nc products of the residual step
919 : CALL cp_cfm_gemm('C', 'N', nmat, nmat, nao, z_one, c_notconv, m_hc, z_zero, h_block, &
920 12447 : c_first_row=1, c_first_col=1)
921 : CALL cp_cfm_gemm('C', 'N', nmat, nmat, nao, z_one, c_notconv, m_sc, z_zero, s_block, &
922 12447 : c_first_row=1, c_first_col=1)
923 :
924 : ! compute ZSC and ZHC with m_sc/m_sc still holding S*C_nc and H*C_nc
925 : CALL cp_cfm_gemm('C', 'N', nmat, nmat, nao, z_one, c_mz, m_sc, z_zero, s_block, &
926 12447 : c_first_row=1 + nmat, c_first_col=1)
927 : ! compute ZHC
928 : CALL cp_cfm_gemm('C', 'N', nmat, nmat, nao, z_one, c_mz, m_hc, z_zero, h_block, &
929 12447 : c_first_row=1 + nmat, c_first_col=1)
930 :
931 : ! then reuse m_sc and m_hc to compute SZ and HZ (mirrors the Gamma
932 : ! version); with frozen converged vectors the operator is the shifted
933 : ! h_fm = H + lambda*P
934 12447 : IF (nmo_converged > 0) THEN
935 484 : CALL cp_cfm_gemm('N', 'N', nao, ncol_z, nao, z_one, h_fm, c_mz, z_zero, m_hc)
936 484 : CALL cp_cfm_release(c_out)
937 484 : CALL cp_cfm_release(h_fm)
938 : ELSE
939 11963 : CALL cp_cfm_gemm('N', 'N', nao, ncol_z, nao, z_one, matrix_h, c_mz, z_zero, m_hc)
940 : END IF
941 12447 : CALL cp_cfm_gemm('N', 'N', nao, ncol_z, nao, z_one, matrix_s, c_mz, z_zero, m_sc)
942 :
943 : ! the opposite off-diagonal blocks are the conjugate transposes
944 : ! (ZSC)^H = C_nc^H*(S*Z) and (ZHC)^H = C_nc^H*(H*Z): with S and H
945 : ! Hermitian these are the same products read in the other direction,
946 : ! so the blocks complete as gemms against the just-computed S*Z and
947 : ! H*Z, with no gather/conjugate/scatter round trip per block (two
948 : ! collectives and a serial conjugation of nmat^2 elements each)
949 : CALL cp_cfm_gemm('C', 'N', nmat, nmat, nao, z_one, c_notconv, m_sc, z_zero, s_block, &
950 12447 : c_first_row=1, c_first_col=1 + nmat)
951 : CALL cp_cfm_gemm('C', 'N', nmat, nmat, nao, z_one, c_notconv, m_hc, z_zero, h_block, &
952 12447 : c_first_row=1, c_first_col=1 + nmat)
953 :
954 : ! compute ZSZ
955 : CALL cp_cfm_gemm('C', 'N', nmat, nmat, nao, z_one, c_mz, m_sc, z_zero, s_block, &
956 12447 : c_first_row=1 + nmat, c_first_col=1 + nmat)
957 : ! compute ZHZ
958 : CALL cp_cfm_gemm('C', 'N', nmat, nmat, nao, z_one, c_mz, m_hc, z_zero, h_block, &
959 12447 : c_first_row=1 + nmat, c_first_col=1 + nmat)
960 :
961 12447 : CALL cp_cfm_release(m_sc)
962 :
963 : ! solution of the reduced generalized eigenproblem
964 12447 : CALL cp_cfm_geeig(h_block, s_block, v_block, evals, w_block)
965 :
966 : ! new MOS: C_nc*V_11 + Z*V_21
967 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmat, &
968 : context=cmo%matrix_struct%context, &
969 12447 : para_env=cmo%matrix_struct%para_env)
970 12447 : CALL cp_cfm_create(c_new, fm_struct_tmp, name="c_new")
971 12447 : CALL cp_fm_struct_release(fm_struct_tmp)
972 : CALL cp_cfm_gemm('N', 'N', nao, nmat, nmat, z_one, c_notconv, v_block, z_zero, c_new, &
973 12447 : b_first_row=1, b_first_col=1)
974 : CALL cp_cfm_gemm('N', 'N', nao, nmat, nmat, z_one, c_mz, v_block, z_one, c_new, &
975 12447 : b_first_row=1 + nmat, b_first_col=1)
976 :
977 12447 : CALL cp_cfm_release(m_hc)
978 12447 : CALL cp_cfm_release(c_mz)
979 12447 : CALL cp_cfm_release(c_z)
980 12447 : CALL cp_cfm_release(c_notconv)
981 12447 : CALL cp_cfm_release(s_block)
982 12447 : CALL cp_cfm_release(h_block)
983 12447 : CALL cp_cfm_release(w_block)
984 12447 : CALL cp_cfm_release(v_block)
985 :
986 12447 : IF (nmo_converged > 0) THEN
987 484 : jj = 1
988 1634 : DO j = 1, nset_not_conv
989 1150 : i_first = inotconv_set(j, 1)
990 1150 : i_last = inotconv_set(j, 2)
991 1150 : n = i_last - i_first + 1
992 4600 : ALLOCATE (submat_buffer(nao, n))
993 : CALL cp_cfm_get_submatrix(c_new, submat_buffer, start_row=1, start_col=jj, &
994 1150 : n_rows=nao, n_cols=n)
995 1150 : CALL cp_cfm_set_submatrix(cmo, submat_buffer, start_row=1, start_col=i_first)
996 1150 : DEALLOCATE (submat_buffer)
997 14344 : eigenvalues(i_first:i_last) = evals(jj:jj + n - 1)
998 1634 : jj = jj + n
999 : END DO
1000 484 : DEALLOCATE (iconv_set)
1001 484 : DEALLOCATE (inotconv_set)
1002 : ELSE
1003 11963 : CALL cp_cfm_to_cfm(c_new, cmo)
1004 405324 : eigenvalues(1:nmo) = evals(1:nmo)
1005 : END IF
1006 12447 : DEALLOCATE (evals)
1007 12447 : CALL cp_cfm_release(c_new)
1008 :
1009 12447 : t2 = m_walltime()
1010 12447 : IF (output_unit > 0) THEN
1011 : WRITE (output_unit, '(T16,I5,T24,I6,T33,E12.4,2x,E12.4,T60,F8.3)') &
1012 0 : iter, nmo_converged, max_norm, min_norm, t2 - t1
1013 : END IF
1014 118657 : t1 = m_walltime()
1015 :
1016 : END DO ! iter
1017 :
1018 1906 : IF (exhausted) THEN
1019 : ! single cleanup point for the interrupted iteration: the shifted
1020 : ! operator h_fm ends its life either here or at the HZ recompute
1021 : ! inside the loop, its two end-of-life sites
1022 148 : IF (nmo_converged > 0) THEN
1023 0 : CALL cp_cfm_release(h_fm)
1024 0 : CALL cp_cfm_release(c_out)
1025 : END IF
1026 148 : CALL cp_cfm_release(m_hc)
1027 148 : CALL cp_cfm_release(m_sc)
1028 148 : CALL cp_cfm_release(c_z)
1029 148 : CALL cp_cfm_release(c_mz)
1030 148 : CALL cp_cfm_release(c_notconv)
1031 148 : IF (ALLOCATED(iconv_set)) DEALLOCATE (iconv_set)
1032 148 : IF (ALLOCATED(inotconv_set)) DEALLOCATE (inotconv_set)
1033 :
1034 : ! the subspace expansion was exhausted (symmetry-invariant MOS span);
1035 : ! finish this channel by a direct diagonalization of the intact
1036 : ! operator, so that at least the rotation inside the MOS span is exact
1037 148 : CALL cp_cfm_create(h_fm, matrix_h%matrix_struct, name="fb_h")
1038 148 : CALL cp_cfm_create(c_out, matrix_h%matrix_struct, name="fb_s")
1039 148 : CALL cp_cfm_create(c_new, matrix_h%matrix_struct, name="fb_work")
1040 148 : CALL cp_cfm_to_cfm(matrix_h, h_fm)
1041 148 : CALL cp_cfm_to_cfm(matrix_s, c_out)
1042 148 : CALL cp_cfm_geeig(h_fm, c_out, cmo, eigenvalues, c_new)
1043 148 : CALL cp_cfm_release(h_fm)
1044 148 : CALL cp_cfm_release(c_out)
1045 148 : CALL cp_cfm_release(c_new)
1046 : END IF
1047 :
1048 1906 : DEALLOCATE (iconv)
1049 1906 : DEALLOCATE (inotconv)
1050 1906 : DEALLOCATE (ritz_coeff)
1051 1906 : DEALLOCATE (vnorm)
1052 1906 : DEALLOCATE (cdiag)
1053 1906 : IF (ALLOCATED(scaling)) DEALLOCATE (scaling)
1054 :
1055 1906 : CALL timestop(handle)
1056 5718 : END SUBROUTINE generate_extended_space_c
1057 :
1058 : ! **************************************************************************************************
1059 : !> \brief ...
1060 : !> \param bdav_env ...
1061 : !> \param mo_set ...
1062 : !> \param matrix_h ...
1063 : !> \param matrix_s ...
1064 : !> \param output_unit ...
1065 : !> \param preconditioner ...
1066 : ! **************************************************************************************************
1067 64 : SUBROUTINE generate_extended_space_sparse(bdav_env, mo_set, matrix_h, matrix_s, output_unit, &
1068 : preconditioner)
1069 :
1070 : TYPE(davidson_type) :: bdav_env
1071 : TYPE(mo_set_type), INTENT(IN) :: mo_set
1072 : TYPE(dbcsr_type), POINTER :: matrix_h, matrix_s
1073 : INTEGER, INTENT(IN) :: output_unit
1074 : TYPE(preconditioner_type), OPTIONAL, POINTER :: preconditioner
1075 :
1076 : CHARACTER(len=*), PARAMETER :: routineN = 'generate_extended_space_sparse'
1077 :
1078 : INTEGER :: col_offset, handle, homo, i_first, i_last, imo, iteration, j, jj, k, max_iter, n, &
1079 : nao, nmat, nmat2, nmo, nmo_converged, nmo_not_converged, nset, nset_conv, nset_not_conv
1080 64 : INTEGER, ALLOCATABLE, DIMENSION(:) :: iconv, inotconv
1081 64 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: iconv_set, inotconv_set
1082 : LOGICAL :: converged, do_apply_preconditioner
1083 : REAL(dp) :: lambda, max_norm, min_norm, t1, t2
1084 64 : REAL(dp), ALLOCATABLE, DIMENSION(:) :: eig_not_conv, evals, ritz_coeff, vnorm
1085 64 : REAL(dp), DIMENSION(:), POINTER :: eigenvalues
1086 64 : REAL(dp), DIMENSION(:, :), POINTER :: block
1087 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
1088 : TYPE(cp_fm_type) :: h_block, matrix_mm_fm, matrix_mmt_fm, &
1089 : matrix_nm_fm, matrix_z_fm, mo_conv_fm, &
1090 : s_block, v_block, w_block
1091 : TYPE(cp_fm_type), POINTER :: mo_coeff, mo_notconv_fm
1092 : TYPE(dbcsr_iterator_type) :: iter
1093 : TYPE(dbcsr_type), POINTER :: c_out, matrix_hc, matrix_mm, matrix_pz, &
1094 : matrix_sc, matrix_z, mo_coeff_b, &
1095 : mo_conv, mo_notconv, smo_conv
1096 : TYPE(mp_comm_type) :: group
1097 :
1098 64 : CALL timeset(routineN, handle)
1099 :
1100 64 : do_apply_preconditioner = .FALSE.
1101 64 : IF (PRESENT(preconditioner)) do_apply_preconditioner = .TRUE.
1102 :
1103 64 : NULLIFY (mo_coeff, mo_coeff_b, matrix_hc, matrix_sc, matrix_z, matrix_pz, matrix_mm)
1104 64 : NULLIFY (mo_notconv_fm, mo_conv, mo_notconv, smo_conv, c_out)
1105 64 : NULLIFY (fm_struct_tmp)
1106 : CALL get_mo_set(mo_set=mo_set, mo_coeff=mo_coeff, mo_coeff_b=mo_coeff_b, &
1107 64 : eigenvalues=eigenvalues, homo=homo, nao=nao, nmo=nmo)
1108 64 : IF (do_apply_preconditioner) THEN
1109 56 : max_iter = bdav_env%max_iter
1110 : ELSE
1111 : max_iter = 1
1112 : END IF
1113 :
1114 64 : t1 = m_walltime()
1115 64 : IF (output_unit > 0) THEN
1116 : WRITE (output_unit, "(T15,A,T23,A,T36,A,T49,A,T60,A,/,T8,A)") &
1117 0 : " Cycle ", " conv. MOS ", " B2MAX ", " B2MIN ", " Time", REPEAT("-", 60)
1118 : END IF
1119 :
1120 : ! Allocate array for Ritz values
1121 192 : ALLOCATE (ritz_coeff(nmo))
1122 192 : ALLOCATE (iconv(nmo))
1123 128 : ALLOCATE (inotconv(nmo))
1124 128 : ALLOCATE (vnorm(nmo))
1125 :
1126 64 : converged = .FALSE.
1127 128 : DO iteration = 1, max_iter
1128 88 : NULLIFY (c_out, mo_conv, mo_notconv_fm, mo_notconv)
1129 : ! Prepare HC and SC, using mo_coeff_b (sparse), these are still sparse
1130 88 : CALL dbcsr_init_p(matrix_hc)
1131 : CALL dbcsr_create(matrix_hc, template=mo_coeff_b, &
1132 : name="matrix_hc", &
1133 88 : matrix_type=dbcsr_type_no_symmetry)
1134 88 : CALL dbcsr_init_p(matrix_sc)
1135 : CALL dbcsr_create(matrix_sc, template=mo_coeff_b, &
1136 : name="matrix_sc", &
1137 88 : matrix_type=dbcsr_type_no_symmetry)
1138 :
1139 88 : CALL dbcsr_get_info(mo_coeff_b, nfullrows_total=n, nfullcols_total=k, group=group)
1140 88 : CALL dbcsr_multiply('n', 'n', 1.0_dp, matrix_h, mo_coeff_b, 0.0_dp, matrix_hc, last_column=k)
1141 88 : CALL dbcsr_multiply('n', 'n', 1.0_dp, matrix_s, mo_coeff_b, 0.0_dp, matrix_sc, last_column=k)
1142 :
1143 : ! compute Ritz values
1144 88 : ritz_coeff = 0.0_dp
1145 : ! Allocate Sparse matrices: nmoxnmo
1146 : ! matrix_mm
1147 :
1148 88 : CALL dbcsr_init_p(matrix_mm)
1149 : CALL cp_dbcsr_m_by_n_from_template(matrix_mm, template=matrix_s, m=nmo, n=nmo, &
1150 88 : sym=dbcsr_type_no_symmetry)
1151 :
1152 88 : CALL dbcsr_multiply('t', 'n', 1.0_dp, mo_coeff_b, matrix_hc, 0.0_dp, matrix_mm, last_column=k)
1153 88 : CALL dbcsr_get_diag(matrix_mm, ritz_coeff)
1154 88 : CALL mo_coeff%matrix_struct%para_env%sum(ritz_coeff)
1155 :
1156 : ! extended subspace P Z = P [H - theta S]C this ia another matrix of type and size as mo_coeff_b
1157 88 : CALL dbcsr_init_p(matrix_z)
1158 : CALL dbcsr_create(matrix_z, template=mo_coeff_b, &
1159 : name="matrix_z", &
1160 88 : matrix_type=dbcsr_type_no_symmetry)
1161 88 : CALL dbcsr_copy(matrix_z, matrix_sc)
1162 88 : CALL dbcsr_scale_by_vector(matrix_z, ritz_coeff, side='right')
1163 88 : CALL dbcsr_add(matrix_z, matrix_hc, -1.0_dp, 1.0_dp)
1164 :
1165 : ! Compute the column norms of matrix_z.
1166 88 : vnorm = 0.0_dp
1167 88 : CALL dbcsr_iterator_start(iter, matrix_z)
1168 792 : DO WHILE (dbcsr_iterator_blocks_left(iter))
1169 704 : CALL dbcsr_iterator_next_block(iter, block=block, col_offset=col_offset)
1170 13464 : DO j = 1, SIZE(block, 2)
1171 178112 : vnorm(col_offset + j - 1) = vnorm(col_offset + j - 1) + SUM(block(:, j)**2)
1172 : END DO
1173 : END DO
1174 88 : CALL dbcsr_iterator_stop(iter)
1175 88 : CALL group%sum(vnorm)
1176 3256 : vnorm = SQRT(vnorm)
1177 :
1178 : ! Check for converged eigenvectors
1179 88 : nmo_converged = 0
1180 88 : nmo_not_converged = 0
1181 88 : max_norm = 0.0_dp
1182 88 : min_norm = 1.e10_dp
1183 3256 : DO imo = 1, nmo
1184 3168 : max_norm = MAX(max_norm, vnorm(imo))
1185 3256 : min_norm = MIN(min_norm, vnorm(imo))
1186 : END DO
1187 88 : iconv = 0
1188 88 : inotconv = 0
1189 :
1190 3256 : DO imo = 1, nmo
1191 3256 : IF (vnorm(imo) <= bdav_env%eps_iter) THEN
1192 836 : nmo_converged = nmo_converged + 1
1193 836 : iconv(nmo_converged) = imo
1194 : ELSE
1195 2332 : nmo_not_converged = nmo_not_converged + 1
1196 2332 : inotconv(nmo_not_converged) = imo
1197 : END IF
1198 : END DO
1199 :
1200 88 : IF (nmo_converged > 0) THEN
1201 90 : ALLOCATE (iconv_set(nmo_converged, 2))
1202 88 : ALLOCATE (inotconv_set(nmo_not_converged, 2))
1203 30 : i_last = iconv(1)
1204 30 : nset = 0
1205 866 : DO j = 1, nmo_converged
1206 836 : imo = iconv(j)
1207 :
1208 866 : IF (imo == i_last + 1) THEN
1209 772 : i_last = imo
1210 772 : iconv_set(nset, 2) = imo
1211 : ELSE
1212 64 : i_last = imo
1213 64 : nset = nset + 1
1214 64 : iconv_set(nset, 1) = imo
1215 64 : iconv_set(nset, 2) = imo
1216 : END IF
1217 : END DO
1218 30 : nset_conv = nset
1219 :
1220 30 : i_last = inotconv(1)
1221 30 : nset = 0
1222 274 : DO j = 1, nmo_not_converged
1223 244 : imo = inotconv(j)
1224 :
1225 274 : IF (imo == i_last + 1) THEN
1226 184 : i_last = imo
1227 184 : inotconv_set(nset, 2) = imo
1228 : ELSE
1229 60 : i_last = imo
1230 60 : nset = nset + 1
1231 60 : inotconv_set(nset, 1) = imo
1232 60 : inotconv_set(nset, 2) = imo
1233 : END IF
1234 : END DO
1235 30 : nset_not_conv = nset
1236 :
1237 30 : CALL dbcsr_release_p(matrix_hc)
1238 30 : CALL dbcsr_release_p(matrix_sc)
1239 30 : CALL dbcsr_release_p(matrix_z)
1240 30 : CALL dbcsr_release_p(matrix_mm)
1241 : END IF
1242 :
1243 88 : IF (REAL(nmo_converged, dp)/REAL(nmo, dp) > bdav_env%conv_percent) THEN
1244 24 : DEALLOCATE (iconv_set)
1245 :
1246 24 : DEALLOCATE (inotconv_set)
1247 :
1248 24 : converged = .TRUE.
1249 24 : t2 = m_walltime()
1250 24 : IF (output_unit > 0) THEN
1251 : WRITE (output_unit, '(T16,I5,T24,I6,T33,E12.4,2x,E12.4,T60,F8.3)') &
1252 0 : iteration, nmo_converged, max_norm, min_norm, t2 - t1
1253 :
1254 0 : WRITE (output_unit, *) " Reached convergence in ", iteration, &
1255 0 : " Davidson iterations"
1256 : END IF
1257 :
1258 : EXIT
1259 : END IF
1260 :
1261 64 : IF (nmo_converged > 0) THEN
1262 :
1263 : !allocate mo_conv_fm
1264 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmo_converged, &
1265 : context=mo_coeff%matrix_struct%context, &
1266 6 : para_env=mo_coeff%matrix_struct%para_env)
1267 6 : CALL cp_fm_create(mo_conv_fm, fm_struct_tmp, name="mo_conv_fm")
1268 :
1269 6 : CALL cp_fm_struct_release(fm_struct_tmp)
1270 :
1271 : ! extract mo_conv from mo_coeff full matrix
1272 6 : jj = 1
1273 22 : DO j = 1, nset_conv
1274 16 : i_first = iconv_set(j, 1)
1275 16 : i_last = iconv_set(j, 2)
1276 16 : n = i_last - i_first + 1
1277 16 : CALL cp_fm_to_fm_submat(mo_coeff, mo_conv_fm, nao, n, 1, i_first, 1, jj)
1278 22 : jj = jj + n
1279 : END DO
1280 :
1281 : ! allocate c_out sparse matrix, to project out the converged MOS
1282 6 : CALL dbcsr_init_p(c_out)
1283 : CALL dbcsr_create(c_out, template=matrix_s, &
1284 : name="c_out", &
1285 6 : matrix_type=dbcsr_type_symmetric)
1286 :
1287 : ! allocate mo_conv sparse
1288 6 : CALL dbcsr_init_p(mo_conv)
1289 : CALL cp_dbcsr_m_by_n_from_row_template(mo_conv, template=matrix_s, n=nmo_converged, &
1290 6 : sym=dbcsr_type_no_symmetry)
1291 :
1292 6 : CALL dbcsr_init_p(smo_conv)
1293 : CALL cp_dbcsr_m_by_n_from_row_template(smo_conv, template=matrix_s, n=nmo_converged, &
1294 6 : sym=dbcsr_type_no_symmetry)
1295 :
1296 6 : CALL copy_fm_to_dbcsr(mo_conv_fm, mo_conv) !fm->dbcsr
1297 :
1298 6 : CALL dbcsr_multiply('n', 'n', 1.0_dp, matrix_s, mo_conv, 0.0_dp, smo_conv, last_column=nmo_converged)
1299 6 : CALL dbcsr_multiply('n', 't', 1.0_dp, smo_conv, smo_conv, 0.0_dp, c_out, last_column=nao)
1300 : ! project c_out out of H
1301 6 : lambda = 100.0_dp*ABS(eigenvalues(homo))
1302 6 : CALL dbcsr_add(c_out, matrix_h, lambda, 1.0_dp)
1303 :
1304 6 : CALL dbcsr_release_p(mo_conv)
1305 6 : CALL dbcsr_release_p(smo_conv)
1306 6 : CALL cp_fm_release(mo_conv_fm)
1307 :
1308 : !allocate c_notconv_fm
1309 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmo_not_converged, &
1310 : context=mo_coeff%matrix_struct%context, &
1311 6 : para_env=mo_coeff%matrix_struct%para_env)
1312 6 : ALLOCATE (mo_notconv_fm)
1313 6 : CALL cp_fm_create(mo_notconv_fm, fm_struct_tmp, name="mo_notconv_fm")
1314 6 : CALL cp_fm_struct_release(fm_struct_tmp)
1315 :
1316 : ! extract mo_notconv from mo_coeff full matrix
1317 18 : ALLOCATE (eig_not_conv(nmo_not_converged))
1318 :
1319 6 : jj = 1
1320 24 : DO j = 1, nset_not_conv
1321 18 : i_first = inotconv_set(j, 1)
1322 18 : i_last = inotconv_set(j, 2)
1323 18 : n = i_last - i_first + 1
1324 18 : CALL cp_fm_to_fm_submat(mo_coeff, mo_notconv_fm, nao, n, 1, i_first, 1, jj)
1325 186 : eig_not_conv(jj:jj + n - 1) = ritz_coeff(i_first:i_last)
1326 24 : jj = jj + n
1327 : END DO
1328 :
1329 : ! allocate mo_conv sparse
1330 6 : CALL dbcsr_init_p(mo_notconv)
1331 : CALL cp_dbcsr_m_by_n_from_row_template(mo_notconv, template=matrix_s, n=nmo_not_converged, &
1332 6 : sym=dbcsr_type_no_symmetry)
1333 :
1334 6 : CALL dbcsr_init_p(matrix_hc)
1335 : CALL cp_dbcsr_m_by_n_from_row_template(matrix_hc, template=matrix_s, n=nmo_not_converged, &
1336 6 : sym=dbcsr_type_no_symmetry)
1337 :
1338 6 : CALL dbcsr_init_p(matrix_sc)
1339 : CALL cp_dbcsr_m_by_n_from_row_template(matrix_sc, template=matrix_s, n=nmo_not_converged, &
1340 6 : sym=dbcsr_type_no_symmetry)
1341 :
1342 6 : CALL dbcsr_init_p(matrix_z)
1343 : CALL cp_dbcsr_m_by_n_from_row_template(matrix_z, template=matrix_s, n=nmo_not_converged, &
1344 6 : sym=dbcsr_type_no_symmetry)
1345 :
1346 6 : CALL copy_fm_to_dbcsr(mo_notconv_fm, mo_notconv) !fm->dbcsr
1347 :
1348 : CALL dbcsr_multiply('n', 'n', 1.0_dp, c_out, mo_notconv, 0.0_dp, matrix_hc, &
1349 6 : last_column=nmo_not_converged)
1350 : CALL dbcsr_multiply('n', 'n', 1.0_dp, matrix_s, mo_notconv, 0.0_dp, matrix_sc, &
1351 6 : last_column=nmo_not_converged)
1352 :
1353 6 : CALL dbcsr_copy(matrix_z, matrix_sc)
1354 6 : CALL dbcsr_scale_by_vector(matrix_z, eig_not_conv, side='right')
1355 6 : CALL dbcsr_add(matrix_z, matrix_hc, -1.0_dp, 1.0_dp)
1356 :
1357 6 : DEALLOCATE (eig_not_conv)
1358 :
1359 : ! matrix_mm
1360 6 : CALL dbcsr_init_p(matrix_mm)
1361 : CALL cp_dbcsr_m_by_n_from_template(matrix_mm, template=matrix_s, m=nmo_not_converged, n=nmo_not_converged, &
1362 6 : sym=dbcsr_type_no_symmetry)
1363 :
1364 : CALL dbcsr_multiply('t', 'n', 1.0_dp, mo_notconv, matrix_hc, 0.0_dp, matrix_mm, &
1365 18 : last_column=nmo_not_converged)
1366 :
1367 : ELSE
1368 58 : mo_notconv => mo_coeff_b
1369 58 : mo_notconv_fm => mo_coeff
1370 58 : c_out => matrix_h
1371 : END IF
1372 :
1373 : ! allocate matrix_pz using as template matrix_z
1374 64 : CALL dbcsr_init_p(matrix_pz)
1375 : CALL dbcsr_create(matrix_pz, template=matrix_z, &
1376 : name="matrix_pz", &
1377 64 : matrix_type=dbcsr_type_no_symmetry)
1378 :
1379 64 : IF (do_apply_preconditioner) THEN
1380 56 : IF (preconditioner%in_use /= 0) THEN
1381 56 : CALL apply_preconditioner(preconditioner, matrix_z, matrix_pz)
1382 : ELSE
1383 0 : CALL dbcsr_copy(matrix_pz, matrix_z)
1384 : END IF
1385 : ELSE
1386 8 : CALL dbcsr_copy(matrix_pz, matrix_z)
1387 : END IF
1388 :
1389 : !allocate NMOxNMO full matrices
1390 64 : nmat = nmo_not_converged
1391 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmat, ncol_global=nmat, &
1392 : context=mo_coeff%matrix_struct%context, &
1393 64 : para_env=mo_coeff%matrix_struct%para_env)
1394 64 : CALL cp_fm_create(matrix_mm_fm, fm_struct_tmp, name="m_tmp_mxm")
1395 64 : CALL cp_fm_create(matrix_mmt_fm, fm_struct_tmp, name="mt_tmp_mxm")
1396 64 : CALL cp_fm_struct_release(fm_struct_tmp)
1397 :
1398 : !allocate 2NMOx2NMO full matrices
1399 64 : nmat2 = 2*nmo_not_converged
1400 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmat2, ncol_global=nmat2, &
1401 : context=mo_coeff%matrix_struct%context, &
1402 64 : para_env=mo_coeff%matrix_struct%para_env)
1403 :
1404 64 : CALL cp_fm_create(s_block, fm_struct_tmp, name="sb")
1405 64 : CALL cp_fm_create(h_block, fm_struct_tmp, name="hb")
1406 64 : CALL cp_fm_create(v_block, fm_struct_tmp, name="vb")
1407 64 : CALL cp_fm_create(w_block, fm_struct_tmp, name="wb")
1408 192 : ALLOCATE (evals(nmat2))
1409 64 : CALL cp_fm_struct_release(fm_struct_tmp)
1410 :
1411 : ! compute CSC
1412 64 : CALL cp_fm_set_all(s_block, 0.0_dp, 1.0_dp)
1413 : ! compute CHC
1414 64 : CALL copy_dbcsr_to_fm(matrix_mm, matrix_mm_fm)
1415 64 : CALL cp_fm_to_fm_submat(matrix_mm_fm, h_block, nmat, nmat, 1, 1, 1, 1)
1416 :
1417 : ! compute the bottom left ZSC (top right is transpose)
1418 64 : CALL dbcsr_multiply('t', 'n', 1.0_dp, matrix_pz, matrix_sc, 0.0_dp, matrix_mm, last_column=nmat)
1419 : ! set the bottom left part of S[C,Z] block matrix ZSC
1420 : !copy sparse to full
1421 64 : CALL copy_dbcsr_to_fm(matrix_mm, matrix_mm_fm)
1422 64 : CALL cp_fm_to_fm_submat(matrix_mm_fm, s_block, nmat, nmat, 1, 1, 1 + nmat, 1)
1423 64 : CALL cp_fm_transpose(matrix_mm_fm, matrix_mmt_fm)
1424 64 : CALL cp_fm_to_fm_submat(matrix_mmt_fm, s_block, nmat, nmat, 1, 1, 1, 1 + nmat)
1425 :
1426 : ! compute the bottom left ZHC (top right is transpose)
1427 64 : CALL dbcsr_multiply('t', 'n', 1.0_dp, matrix_pz, matrix_hc, 0.0_dp, matrix_mm, last_column=nmat)
1428 : ! set the bottom left part of S[C,Z] block matrix ZHC
1429 64 : CALL copy_dbcsr_to_fm(matrix_mm, matrix_mm_fm)
1430 64 : CALL cp_fm_to_fm_submat(matrix_mm_fm, h_block, nmat, nmat, 1, 1, 1 + nmat, 1)
1431 64 : CALL cp_fm_transpose(matrix_mm_fm, matrix_mmt_fm)
1432 64 : CALL cp_fm_to_fm_submat(matrix_mmt_fm, h_block, nmat, nmat, 1, 1, 1, 1 + nmat)
1433 :
1434 64 : CALL cp_fm_release(matrix_mmt_fm)
1435 :
1436 : ! (reuse matrix_sc and matrix_hc to computr HZ and SZ)
1437 64 : CALL dbcsr_get_info(matrix_pz, nfullrows_total=n, nfullcols_total=k)
1438 64 : CALL dbcsr_multiply('n', 'n', 1.0_dp, c_out, matrix_pz, 0.0_dp, matrix_hc, last_column=k)
1439 64 : CALL dbcsr_multiply('n', 'n', 1.0_dp, matrix_s, matrix_pz, 0.0_dp, matrix_sc, last_column=k)
1440 :
1441 : ! compute the bottom right ZSZ
1442 64 : CALL dbcsr_multiply('t', 'n', 1.0_dp, matrix_pz, matrix_sc, 0.0_dp, matrix_mm, last_column=k)
1443 : ! set the bottom right part of S[C,Z] block matrix ZSZ
1444 64 : CALL copy_dbcsr_to_fm(matrix_mm, matrix_mm_fm)
1445 64 : CALL cp_fm_to_fm_submat(matrix_mm_fm, s_block, nmat, nmat, 1, 1, 1 + nmat, 1 + nmat)
1446 :
1447 : ! compute the bottom right ZHZ
1448 64 : CALL dbcsr_multiply('t', 'n', 1.0_dp, matrix_pz, matrix_hc, 0.0_dp, matrix_mm, last_column=k)
1449 : ! set the bottom right part of H[C,Z] block matrix ZHZ
1450 64 : CALL copy_dbcsr_to_fm(matrix_mm, matrix_mm_fm)
1451 64 : CALL cp_fm_to_fm_submat(matrix_mm_fm, h_block, nmat, nmat, 1, 1, 1 + nmat, 1 + nmat)
1452 :
1453 64 : CALL dbcsr_release_p(matrix_mm)
1454 64 : CALL dbcsr_release_p(matrix_sc)
1455 64 : CALL dbcsr_release_p(matrix_hc)
1456 :
1457 64 : CALL reduce_extended_space(s_block, h_block, v_block, w_block, evals, nmat2)
1458 :
1459 : ! allocate two (nao x nmat) full matrix
1460 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nmat, &
1461 : context=mo_coeff%matrix_struct%context, &
1462 64 : para_env=mo_coeff%matrix_struct%para_env)
1463 64 : CALL cp_fm_create(matrix_nm_fm, fm_struct_tmp, name="m_nxm")
1464 64 : CALL cp_fm_create(matrix_z_fm, fm_struct_tmp, name="m_nxm")
1465 64 : CALL cp_fm_struct_release(fm_struct_tmp)
1466 :
1467 64 : CALL copy_dbcsr_to_fm(matrix_pz, matrix_z_fm)
1468 : ! extract egenvectors
1469 64 : CALL cp_fm_to_fm_submat(v_block, matrix_mm_fm, nmat, nmat, 1, 1, 1, 1)
1470 64 : CALL parallel_gemm('N', 'N', nao, nmat, nmat, 1.0_dp, mo_notconv_fm, matrix_mm_fm, 0.0_dp, matrix_nm_fm)
1471 64 : CALL cp_fm_to_fm_submat(v_block, matrix_mm_fm, nmat, nmat, 1 + nmat, 1, 1, 1)
1472 64 : CALL parallel_gemm('N', 'N', nao, nmat, nmat, 1.0_dp, matrix_z_fm, matrix_mm_fm, 1.0_dp, matrix_nm_fm)
1473 :
1474 64 : CALL dbcsr_release_p(matrix_z)
1475 64 : CALL dbcsr_release_p(matrix_pz)
1476 64 : CALL cp_fm_release(matrix_z_fm)
1477 64 : CALL cp_fm_release(s_block)
1478 64 : CALL cp_fm_release(h_block)
1479 64 : CALL cp_fm_release(w_block)
1480 64 : CALL cp_fm_release(v_block)
1481 64 : CALL cp_fm_release(matrix_mm_fm)
1482 :
1483 : ! in case some vector are already converged only a subset of vectors are copied in the MOS
1484 64 : IF (nmo_converged > 0) THEN
1485 6 : jj = 1
1486 24 : DO j = 1, nset_not_conv
1487 18 : i_first = inotconv_set(j, 1)
1488 18 : i_last = inotconv_set(j, 2)
1489 18 : n = i_last - i_first + 1
1490 18 : CALL cp_fm_to_fm_submat(matrix_nm_fm, mo_coeff, nao, n, 1, jj, 1, i_first)
1491 186 : eigenvalues(i_first:i_last) = evals(jj:jj + n - 1)
1492 24 : jj = jj + n
1493 : END DO
1494 6 : DEALLOCATE (iconv_set)
1495 6 : DEALLOCATE (inotconv_set)
1496 :
1497 6 : CALL dbcsr_release_p(mo_notconv)
1498 6 : CALL dbcsr_release_p(c_out)
1499 6 : CALL cp_fm_release(mo_notconv_fm)
1500 6 : DEALLOCATE (mo_notconv_fm)
1501 : ELSE
1502 58 : CALL cp_fm_to_fm(matrix_nm_fm, mo_coeff)
1503 2146 : eigenvalues(1:nmo) = evals(1:nmo)
1504 : END IF
1505 64 : DEALLOCATE (evals)
1506 :
1507 64 : CALL cp_fm_release(matrix_nm_fm)
1508 64 : CALL copy_fm_to_dbcsr(mo_coeff, mo_coeff_b) !fm->dbcsr
1509 :
1510 64 : t2 = m_walltime()
1511 64 : IF (output_unit > 0) THEN
1512 : WRITE (output_unit, '(T16,I5,T24,I6,T33,E12.4,2x,E12.4,T60,F8.3)') &
1513 0 : iteration, nmo_converged, max_norm, min_norm, t2 - t1
1514 : END IF
1515 536 : t1 = m_walltime()
1516 :
1517 : END DO ! iteration
1518 :
1519 64 : DEALLOCATE (ritz_coeff)
1520 64 : DEALLOCATE (iconv)
1521 64 : DEALLOCATE (inotconv)
1522 64 : DEALLOCATE (vnorm)
1523 :
1524 64 : CALL timestop(handle)
1525 :
1526 192 : END SUBROUTINE generate_extended_space_sparse
1527 :
1528 : ! **************************************************************************************************
1529 :
1530 : ! **************************************************************************************************
1531 : !> \brief ...
1532 : !> \param s_block ...
1533 : !> \param h_block ...
1534 : !> \param v_block ...
1535 : !> \param w_block ...
1536 : !> \param evals ...
1537 : !> \param ndim ...
1538 : ! **************************************************************************************************
1539 148 : SUBROUTINE reduce_extended_space(s_block, h_block, v_block, w_block, evals, ndim)
1540 :
1541 : TYPE(cp_fm_type), INTENT(IN) :: s_block, h_block, v_block, w_block
1542 : REAL(dp), DIMENSION(:) :: evals
1543 : INTEGER :: ndim
1544 :
1545 : CHARACTER(len=*), PARAMETER :: routineN = 'reduce_extended_space'
1546 :
1547 : INTEGER :: handle, info
1548 :
1549 148 : CALL timeset(routineN, handle)
1550 :
1551 148 : CALL cp_fm_to_fm(s_block, w_block)
1552 148 : CALL cp_fm_cholesky_decompose(s_block, info_out=info)
1553 148 : IF (info == 0) THEN
1554 148 : CALL cp_fm_triangular_invert(s_block)
1555 148 : CALL cp_fm_cholesky_restore(H_block, ndim, S_block, w_block, "MULTIPLY", pos="RIGHT")
1556 148 : CALL cp_fm_cholesky_restore(w_block, ndim, S_block, H_block, "MULTIPLY", pos="LEFT", transa="T")
1557 148 : CALL choose_eigv_solver(H_block, w_block, evals)
1558 148 : CALL cp_fm_cholesky_restore(w_block, ndim, S_block, v_block, "MULTIPLY")
1559 : ELSE
1560 : ! S^(-1/2)
1561 0 : CALL cp_fm_power(w_block, s_block, -0.5_dp, 1.0E-5_dp, info)
1562 0 : CALL cp_fm_to_fm(w_block, s_block)
1563 0 : CALL parallel_gemm('N', 'N', ndim, ndim, ndim, 1.0_dp, H_block, s_block, 0.0_dp, w_block)
1564 0 : CALL parallel_gemm('N', 'N', ndim, ndim, ndim, 1.0_dp, s_block, w_block, 0.0_dp, H_block)
1565 0 : CALL choose_eigv_solver(H_block, w_block, evals)
1566 0 : CALL parallel_gemm('N', 'N', ndim, ndim, ndim, 1.0_dp, s_block, w_block, 0.0_dp, v_block)
1567 : END IF
1568 :
1569 148 : CALL timestop(handle)
1570 :
1571 148 : END SUBROUTINE reduce_extended_space
1572 :
1573 : END MODULE qs_scf_block_davidson
|