(git:c641773)
Loading...
Searching...
No Matches
qs_scf_lanczos_c.F
Go to the documentation of this file.
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 Complex block-Lanczos refinement kernel for k-point SCF
10!> diagonalization. Processes unconverged columns in blocks of
11!> NBLOCK with two-pass DGKS reorthogonalization against the
12!> working basis and deflation prefix, BLAS-3 CholeskyQR2 batch
13!> orthonormalization (with CGS2 fallback on rank-deficient
14!> batches), and an explicit Hermitian Rayleigh-Ritz projection
15!> T = V^dag(A V). Scratch matrices and local LAPACK buffers live
16!> in a caller-owned workspace reused across sweeps.
17! **************************************************************************************************
25 USE cp_cfm_diag, ONLY: cp_cfm_heevd
26 USE cp_cfm_types, ONLY: cp_cfm_create,&
34 USE kinds, ONLY: dp
35 USE mathconstants, ONLY: z_mone,&
36 z_one,&
37 z_zero
39#include "./base/base_uses.f90"
40
41 IMPLICIT NONE
42 PRIVATE
43
44 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_scf_lanczos_c'
45 INTEGER, PARAMETER, PRIVATE :: shared_budget_factor = 4
46
50
51! **************************************************************************************************
52!> \brief Caller-owned scratch of the refinement kernel: every matrix and
53!> array that the sweeps of one channel reuse. The driver creates
54!> the workspace once per diagonalization call and hands it to
55!> every kernel call. The widths follow the worst case of the run.
56!> The basis budget holds the larger of the NKRYLOV block budget
57!> and four times the widest single block, and every per-call
58!> clamp stays below it. The small Rayleigh-Ritz pair keeps its
59!> per-block right-sized allocation, because the solver stack
60!> diagonalizes whole matrices and knows no leading-block argument
61! **************************************************************************************************
62 TYPE, PUBLIC :: lanczos_workspace_type
63 ! entry Rayleigh-Ritz, its rotation and the shared scratch
64 TYPE(cp_cfm_type) :: hmo, mo_gram, evec, rot_scr
65 ! working basis and its A-images
66 TYPE(cp_cfm_type) :: vmat, hvmat
67 ! candidate block, within-batch scratch column, batch Gram, deflation and
68 ! projection-coefficient scratch
69 TYPE(cp_cfm_type) :: cand_blk, one_col, batch_gram, proj_coeff, defl_coeff
70 REAL(dp), ALLOCATABLE :: theta(:), nrm(:), rank_scale(:), pair_res(:), entry_res(:)
71 LOGICAL, ALLOCATABLE :: ldone(:)
72 COMPLEX(dp), ALLOCATABLE :: eval_scale(:)
74
75CONTAINS
76
77! **************************************************************************************************
78!> \brief Refine the non-converged columns of c0 on the standardized operator ks.
79!> The entry Rayleigh-Ritz pass updates the convergence statistics.
80!> Every non-converged column block then runs a single-pass
81!> Lanczos refinement. A full Cholesky sweep closes the call.
82!> \param ks standardized operator A = U^-dag H U^-1, nao x nao
83!> \param c0 current MOS in the standardized basis, refined in place.
84!> The matrix dimensions of the call follow c0
85!> \param eval eigenvalues of c0, updated in place by the entry Rayleigh-Ritz
86!> \param eps_col per-column convergence thresholds on the residual norms:
87!> the driver assigns the relaxed empty threshold to the unoccupied
88!> columns. The occupation decides, not the column index. This
89!> mirrors the Davidson k-point driver
90!> \param nkrylov number of block expansion steps in the block regime.
91!> The kernel uses it as a floor on the budget only when NBLOCK
92!> covers every pending column
93!> \param nblock number of columns refined jointly, one or more
94!> \param ws caller-owned scratch of the call, created by the driver at
95!> the worst-case widths of the run
96!> \param max_res_norm largest residual column norm on exit: the entry
97!> Rayleigh-Ritz values, or the wanted-pair residuals of the
98!> refinement blocks when a refinement ran
99!> \param min_res_norm smallest residual column norm on exit (same basis)
100!> \param nmo_conv number of leading converged columns on exit
101!> \param nmo_nc columns outside the leading converged prefix: every
102!> still-unconverged column, plus converged columns beyond a gap.
103!> The count stays conservative for the not-converged reporting
104!> \param check_moconv_only only run the entry Rayleigh-Ritz and the
105!> convergence count, skip the refinement
106! **************************************************************************************************
107 SUBROUTINE lanczos_refinement_2v_c(ks, c0, eval, eps_col, nkrylov, nblock, ws, &
108 max_res_norm, min_res_norm, nmo_conv, nmo_nc, check_moconv_only)
109
110 TYPE(cp_cfm_type), INTENT(IN) :: ks
111 TYPE(cp_cfm_type), INTENT(INOUT) :: c0
112 REAL(dp), DIMENSION(:), POINTER :: eval
113 REAL(dp), DIMENSION(:), INTENT(IN) :: eps_col
114 INTEGER, INTENT(IN) :: nkrylov, nblock
115 TYPE(lanczos_workspace_type), INTENT(INOUT) :: ws
116 REAL(dp), INTENT(OUT) :: max_res_norm, min_res_norm
117 INTEGER, INTENT(OUT) :: nmo_conv, nmo_nc
118 LOGICAL, INTENT(IN), OPTIONAL :: check_moconv_only
119
120 CHARACTER(LEN=*), PARAMETER :: routinen = 'lanczos_refinement_2v_c'
121
122 INTEGER :: handle
123 LOGICAL :: my_check_moconv_only, next_suffix_rr, &
124 refined
125
126 CALL timeset(routinen, handle)
127
128 my_check_moconv_only = .false.
129 IF (PRESENT(check_moconv_only)) my_check_moconv_only = check_moconv_only
130
131 CALL lanczos_channel_begin(ks, c0, eval, eps_col, ws, max_res_norm, min_res_norm, &
132 nmo_conv, nmo_nc, check_moconv_only=my_check_moconv_only)
133
134 IF (.NOT. my_check_moconv_only) THEN
135 refined = .false.
136 IF (nmo_nc > 0) THEN
137 CALL lanczos_sweep_suffix(ks, c0, eval, eps_col, nkrylov, nblock, .true., .false., &
138 ws, max_res_norm, min_res_norm, nmo_conv, nmo_nc, &
139 refined, next_suffix_rr)
140 END IF
141 IF (refined) THEN
142 CALL lanczos_channel_end(c0, ws)
143 END IF
144 END IF
145
146 CALL timestop(handle)
147 END SUBROUTINE lanczos_refinement_2v_c
148
149! **************************************************************************************************
150!> \brief Entry preparation of one (k-point, spin) channel before its inner
151!> Lanczos sweeps: orthonormalizes the input MOS (skipped for a
152!> read-only convergence probe), runs the full-width entry
153!> Rayleigh-Ritz pass, and computes the initial leading converged
154!> prefix and residual bounds.
155!> \param ks standardized operator A = U^-dag H U^-1, nao x nao
156!> \param c0 current MOS in the standardized basis, rotated in place
157!> \param eval eigenvalues of c0, updated in place
158!> \param eps_col per-column convergence thresholds
159!> \param ws caller-owned channel workspace
160!> \param max_res_norm largest entry residual norm
161!> \param min_res_norm smallest entry residual norm
162!> \param nmo_conv number of leading converged columns on entry
163!> \param nmo_nc number of columns outside the leading converged prefix
164!> \param check_moconv_only skip the entry Cholesky orthonormalization for
165!> a read-only probe
166! **************************************************************************************************
167 SUBROUTINE lanczos_channel_begin(ks, c0, eval, eps_col, ws, max_res_norm, min_res_norm, &
168 nmo_conv, nmo_nc, check_moconv_only)
169 TYPE(cp_cfm_type), INTENT(IN) :: ks
170 TYPE(cp_cfm_type), INTENT(INOUT) :: c0
171 REAL(dp), DIMENSION(:), POINTER :: eval
172 REAL(dp), DIMENSION(:), INTENT(IN) :: eps_col
173 TYPE(lanczos_workspace_type), INTENT(INOUT) :: ws
174 REAL(dp), INTENT(OUT) :: max_res_norm, min_res_norm
175 INTEGER, INTENT(OUT) :: nmo_conv, nmo_nc
176 LOGICAL, INTENT(IN), OPTIONAL :: check_moconv_only
177
178 CHARACTER(LEN=*), PARAMETER :: routinen = 'lanczos_channel_begin'
179
180 INTEGER :: handle, info, iwork, nao, nmo
181 LOGICAL :: my_check_moconv_only
182
183 CALL timeset(routinen, handle)
184
185 CALL cp_cfm_get_info(c0, nrow_global=nao, ncol_global=nmo)
186
187 my_check_moconv_only = .false.
188 IF (PRESENT(check_moconv_only)) my_check_moconv_only = check_moconv_only
189
190 IF (.NOT. my_check_moconv_only) THEN
191 CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, c0, c0, z_zero, ws%mo_gram)
192 CALL cp_cfm_cholesky_decompose(ws%mo_gram, nmo, info)
193 IF (info /= 0) THEN
194 CALL cp_abort(__location__, &
195 "The Gram matrix of the entry MOS lost positive definiteness.")
196 END IF
197 CALL cp_cfm_triangular_multiply(ws%mo_gram, c0, 'R', invert_tr=.true.)
198 END IF
199
200 CALL cp_cfm_gemm('N', 'N', nao, nmo, nao, z_one, ks, c0, z_zero, ws%hmo)
201 CALL rayleigh_ritz(ws%hmo, c0, nmo, nmo, eval, ws%mo_gram, ws%evec, &
202 ws%eval_scale, ws%rot_scr, 1, ws%entry_res)
203
204 nmo_conv = 0
205 nmo_nc = 0
206 max_res_norm = maxval(ws%entry_res(1:nmo))
207 min_res_norm = minval(ws%entry_res(1:nmo))
208 DO iwork = 1, nmo
209 IF (ws%entry_res(iwork) <= eps_col(iwork)) THEN
210 nmo_conv = nmo_conv + 1
211 ELSE
212 nmo_nc = nmo - nmo_conv
213 EXIT
214 END IF
215 END DO
216
217 CALL timestop(handle)
218 END SUBROUTINE lanczos_channel_begin
219
220! **************************************************************************************************
221!> \brief Run one inner Lanczos sweep on the unconverged suffix of c0.
222!> When the previous sweep ran in multi-block mode or had a
223!> truncated block, a local suffix Rayleigh-Ritz pass first
224!> decouples the unconverged tail of width nmo_nc without touching
225!> the locked prefix 1..nmo_conv.
226!> \param ks standardized operator, nao x nao
227!> \param c0 MOS, refined in place on columns nmo_conv+1..nmo
228!> \param eval eigenvalues, updated in place on the unconverged suffix
229!> \param eps_col per-column convergence thresholds
230!> \param nkrylov number of block expansion steps in the block regime
231!> \param nblock number of columns refined jointly
232!> \param first_sweep true on the first sweep right after lanczos_channel_begin
233!> \param need_suffix_rr whether to run a local suffix Rayleigh-Ritz before
234!> refining
235!> \param ws caller-owned channel workspace
236!> \param max_res_norm largest residual norm of the active suffix on exit
237!> \param min_res_norm smallest residual norm of the active suffix on exit
238!> \param nmo_conv leading converged column count, advanced in place
239!> \param nmo_nc unconverged suffix width, updated in place
240!> \param step_refined whether this sweep modified c0
241!> \param next_need_suffix_rr whether the next sweep requires a suffix RR
242! **************************************************************************************************
243 SUBROUTINE lanczos_sweep_suffix(ks, c0, eval, eps_col, nkrylov, nblock, first_sweep, &
244 need_suffix_rr, ws, max_res_norm, min_res_norm, &
245 nmo_conv, nmo_nc, step_refined, next_need_suffix_rr)
246 TYPE(cp_cfm_type), INTENT(IN) :: ks
247 TYPE(cp_cfm_type), INTENT(INOUT) :: c0
248 REAL(dp), DIMENSION(:), POINTER :: eval
249 REAL(dp), DIMENSION(:), INTENT(IN) :: eps_col
250 INTEGER, INTENT(IN) :: nkrylov, nblock
251 LOGICAL, INTENT(IN) :: first_sweep, need_suffix_rr
252 TYPE(lanczos_workspace_type), INTENT(INOUT) :: ws
253 REAL(dp), INTENT(INOUT) :: max_res_norm, min_res_norm
254 INTEGER, INTENT(INOUT) :: nmo_conv, nmo_nc
255 LOGICAL, INTENT(OUT) :: step_refined, next_need_suffix_rr
256
257 CHARACTER(LEN=*), PARAMETER :: routinen = 'lanczos_sweep_suffix'
258
259 INTEGER :: handle, n_conv_cols, nao, nmo_converged, &
260 nmo_nc_loc
261 LOGICAL :: refined, skip_first_defl
262 REAL(dp) :: prev_max, prev_min
263
264 CALL timeset(routinen, handle)
265
266 CALL cp_cfm_get_info(c0, nrow_global=nao)
267
268 step_refined = .false.
269 next_need_suffix_rr = .false.
270
271 IF (need_suffix_rr .AND. nmo_nc > 0) THEN
272 CALL suffix_rayleigh_ritz(ks, c0, eval, eps_col, ws, nmo_conv, nmo_nc, &
273 max_res_norm, min_res_norm)
274 step_refined = .true.
275 IF (nmo_nc == 0) THEN
276 CALL timestop(handle)
277 RETURN
278 END IF
279 END IF
280
281 IF (nmo_nc > 0) THEN
282 prev_max = max_res_norm
283 prev_min = min_res_norm
284 nmo_converged = nmo_conv
285 nmo_nc_loc = nmo_nc
286 skip_first_defl = first_sweep .OR. need_suffix_rr
287 CALL lanczos_refine(ks, c0, eval, nao, eps_col, nkrylov, nblock, &
288 nmo_converged, nmo_nc_loc, skip_first_defl, n_conv_cols, &
289 max_res_norm, min_res_norm, refined, next_need_suffix_rr, ws)
290 IF (.NOT. refined) THEN
291 max_res_norm = prev_max
292 min_res_norm = prev_min
293 ELSE
294 step_refined = .true.
295 END IF
296 nmo_conv = nmo_converged + n_conv_cols
297 nmo_nc = nmo_nc_loc - n_conv_cols
298 END IF
299
300 CALL timestop(handle)
301 END SUBROUTINE lanczos_sweep_suffix
302
303! **************************************************************************************************
304!> \brief Defensive full-width Cholesky orthonormalization at the end of a
305!> channel's refinement sweeps, executed at most once per channel.
306!> \param c0 refined MOS in the standardized basis
307!> \param ws caller-owned channel workspace
308! **************************************************************************************************
309 SUBROUTINE lanczos_channel_end(c0, ws)
310 TYPE(cp_cfm_type), INTENT(INOUT) :: c0
311 TYPE(lanczos_workspace_type), INTENT(INOUT) :: ws
312
313 CHARACTER(LEN=*), PARAMETER :: routinen = 'lanczos_channel_end'
314
315 INTEGER :: handle, info, nao, nmo
316
317 CALL timeset(routinen, handle)
318
319 CALL cp_cfm_get_info(c0, nrow_global=nao, ncol_global=nmo)
320 CALL cp_cfm_gemm('C', 'N', nmo, nmo, nao, z_one, c0, c0, z_zero, ws%mo_gram)
321 CALL cp_cfm_cholesky_decompose(ws%mo_gram, nmo, info)
322 IF (info /= 0) THEN
323 CALL cp_abort(__location__, &
324 "The Gram matrix of the refined set lost positive definiteness.")
325 END IF
326 CALL cp_cfm_triangular_multiply(ws%mo_gram, c0, 'R', invert_tr=.true.)
327
328 CALL timestop(handle)
329 END SUBROUTINE lanczos_channel_end
330
331! **************************************************************************************************
332!> \brief Orthonormalize and run a local Rayleigh-Ritz pass on the
333!> unconverged suffix c0(:, nmo_conv+1:nmo) after a multi-block or
334!> truncated sweep, advancing nmo_conv if newly decoupled pairs meet
335!> eps_col.
336!> \param ks standardized operator, nao x nao
337!> \param c0 MOS, updated in place on the suffix nmo_conv+1..nmo
338!> \param eval eigenvalues, updated in place on the suffix
339!> \param eps_col per-column convergence thresholds
340!> \param ws caller-owned channel workspace
341!> \param nmo_conv leading converged count, advanced in place
342!> \param nmo_nc unconverged suffix width, updated in place
343!> \param max_res_norm largest residual norm of the suffix
344!> \param min_res_norm smallest residual norm of the suffix
345! **************************************************************************************************
346 SUBROUTINE suffix_rayleigh_ritz(ks, c0, eval, eps_col, ws, nmo_conv, nmo_nc, &
347 max_res_norm, min_res_norm)
348 TYPE(cp_cfm_type), INTENT(IN) :: ks
349 TYPE(cp_cfm_type), INTENT(INOUT) :: c0
350 REAL(dp), DIMENSION(:), POINTER :: eval
351 REAL(dp), DIMENSION(:), INTENT(IN) :: eps_col
352 TYPE(lanczos_workspace_type), INTENT(INOUT) :: ws
353 INTEGER, INTENT(INOUT) :: nmo_conv, nmo_nc
354 REAL(dp), INTENT(OUT) :: max_res_norm, min_res_norm
355
356 INTEGER :: col_lo, info, ipass, iwork, m, nao, nmo
357 TYPE(cp_cfm_type) :: esolve, hsolve
358 TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
359
360 NULLIFY (fm_struct_tmp)
361 CALL cp_cfm_get_info(c0, nrow_global=nao, ncol_global=nmo)
362
363 col_lo = nmo_conv + 1
364 m = nmo_nc
365
366 CALL cp_cfm_to_cfm(c0, ws%rot_scr, m, col_lo, 1)
367 IF (nmo_conv > 0) THEN
368 DO ipass = 1, 2
369 CALL cp_cfm_gemm('C', 'N', nmo_conv, m, nao, z_one, c0, ws%rot_scr, z_zero, ws%mo_gram)
370 CALL cp_cfm_gemm('N', 'N', nao, m, nmo_conv, z_mone, c0, ws%mo_gram, z_one, ws%rot_scr)
371 END DO
372 END IF
373 CALL cp_cfm_gemm('C', 'N', m, m, nao, z_one, ws%rot_scr, ws%rot_scr, z_zero, ws%mo_gram)
374 CALL cp_cfm_cholesky_decompose(ws%mo_gram, m, info)
375 IF (info /= 0) THEN
376 CALL cp_abort(__location__, &
377 "The Gram matrix of the suffix MOS lost positive definiteness.")
378 END IF
379 CALL cp_cfm_triangular_multiply(ws%mo_gram, ws%rot_scr, side='R', invert_tr=.true., &
380 n_rows=nao, n_cols=m)
381 CALL cp_cfm_to_cfm(ws%rot_scr, c0, m, 1, col_lo)
382
383 CALL cp_cfm_gemm('N', 'N', nao, m, nao, z_one, ks, c0, z_zero, ws%hmo, b_first_col=col_lo)
384 IF (m == nmo) THEN
385 CALL rayleigh_ritz(ws%hmo, c0, m, m, eval(col_lo:nmo), ws%mo_gram, ws%evec, &
386 ws%eval_scale, ws%rot_scr, col_lo, ws%entry_res, bas_col=col_lo)
387 ELSE
388 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=m, ncol_global=m, &
389 para_env=c0%matrix_struct%para_env, &
390 context=c0%matrix_struct%context)
391 CALL cp_cfm_create(hsolve, matrix_struct=fm_struct_tmp, name="lan_sh", set_zero=.true.)
392 CALL cp_cfm_create(esolve, matrix_struct=fm_struct_tmp, name="lan_se", set_zero=.true.)
393 CALL cp_fm_struct_release(fm_struct_tmp)
394 CALL rayleigh_ritz(ws%hmo, c0, m, m, eval(col_lo:nmo), hsolve, esolve, &
395 ws%eval_scale, ws%rot_scr, col_lo, ws%entry_res, bas_col=col_lo)
396 CALL cp_cfm_release(hsolve)
397 CALL cp_cfm_release(esolve)
398 END IF
399
400 max_res_norm = maxval(ws%entry_res(1:m))
401 min_res_norm = minval(ws%entry_res(1:m))
402 DO iwork = 1, m
403 IF (ws%entry_res(iwork) <= eps_col(col_lo + iwork - 1)) THEN
404 nmo_conv = nmo_conv + 1
405 ELSE
406 EXIT
407 END IF
408 END DO
409 nmo_nc = nmo - nmo_conv
410 END SUBROUTINE suffix_rayleigh_ritz
411
412! **************************************************************************************************
413!> \brief Per-block single-pass Lanczos refinement on the unconverged tail.
414!> Processes non-converged columns in blocks of nblock, expanding
415!> each seed block by A-images with two-pass DGKS reorthogonalization
416!> against the working basis and deflation prefix, and solving the
417!> projected Hermitian Rayleigh-Ritz problem T = V^dag(A V).
418!> \param ks standardized operator, nao x nao
419!> \param c0 MOS, refined in place block by block
420!> \param eval eigenvalues, updated per converged column
421!> \param nao number of atomic orbitals
422!> \param eps_col per-column convergence thresholds
423!> \param nkrylov number of block expansion steps in the block regime
424!> \param nblock number of columns refined jointly
425!> \param nmo_converged number of leading locked columns
426!> \param nmo_nc_loc number of non-converged tail columns
427!> \param skip_first_defl skip deflation on the first seed block when the
428!> suffix just underwent a Rayleigh-Ritz rotation
429!> \param n_conv_cols length of the leading converged run across blocks
430!> \param max_res_norm largest residual norm among the wanted pairs
431!> \param min_res_norm smallest residual norm among the wanted pairs
432!> \param refined whether any block completed a Rayleigh-Ritz pass
433!> \param need_suffix_rr whether a subsequent sweep must run a suffix RR
434!> (multi-block run or any block truncated below its target width)
435!> \param ws caller-owned scratch of the call. Only the small
436!> Rayleigh-Ritz pair stays local to a block, at its right size,
437!> because the solver stack diagonalizes whole matrices
438! **************************************************************************************************
439 SUBROUTINE lanczos_refine(ks, c0, eval, nao, eps_col, nkrylov, nblock, &
440 nmo_converged, nmo_nc_loc, skip_first_defl, n_conv_cols, &
441 max_res_norm, min_res_norm, refined, need_suffix_rr, ws)
442 TYPE(cp_cfm_type), INTENT(IN) :: ks
443 TYPE(cp_cfm_type), INTENT(INOUT) :: c0
444 REAL(dp), DIMENSION(:), POINTER :: eval
445 INTEGER, INTENT(IN) :: nao
446 REAL(dp), DIMENSION(:), INTENT(IN) :: eps_col
447 INTEGER, INTENT(IN) :: nkrylov, nblock, nmo_converged, &
448 nmo_nc_loc
449 LOGICAL, INTENT(IN) :: skip_first_defl
450 INTEGER, INTENT(OUT) :: n_conv_cols
451 REAL(dp), INTENT(OUT) :: max_res_norm, min_res_norm
452 LOGICAL, INTENT(OUT) :: refined, need_suffix_rr
453 TYPE(lanczos_workspace_type), INTENT(INOUT) :: ws
454
455 CHARACTER(LEN=*), PARAMETER :: routinen = 'lanczos_refine'
456
457 INTEGER :: col_hi, col_lo, handle, ib, j, nbasis, &
458 nblock_e, nbmax, nmob_c, nmobt, nres, &
459 nseed, nstep
460 LOGICAL :: any_truncated, prefix_open, single_block
461 TYPE(cp_blacs_env_type), POINTER :: blacs_env
462 TYPE(cp_cfm_type) :: esolve, hsolve
463 TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
464 TYPE(mp_para_env_type), POINTER :: para_env
465
466 CALL timeset(routinen, handle)
467
468 NULLIFY (fm_struct_tmp, blacs_env, para_env)
469 para_env => c0%matrix_struct%para_env
470 blacs_env => c0%matrix_struct%context
471
472 nblock_e = min(max(nblock, 1), max(nmo_nc_loc, 1))
473 single_block = nblock_e >= nmo_nc_loc
474 IF (single_block) THEN
475 ! one block covers every pending column: the Krylov budget holds
476 ! about four times the pending width, floored at NKRYLOV and at
477 ! the block width. The shared subspace holds every target pair
478 ! plus a threefold expansion room. NKRYLOV plays no role here
479 nbmax = min(nao - 2, max(shared_budget_factor*nmo_nc_loc, nkrylov, nblock_e + 2))
480 ELSE
481 nbmax = nkrylov*nblock_e
482 END IF
483 IF (nbmax < 2) THEN
484 ! no working basis beyond the seed exists (nao below four, or a
485 ! degenerate NKRYLOV/NBLOCK combination): leave the columns at
486 ! their entry state for the caller to report, instead of aborting
487 n_conv_cols = 0
488 max_res_norm = 0.0_dp
489 min_res_norm = huge(1.0_dp)
490 refined = .false.
491 need_suffix_rr = .false.
492 cpwarn("Krylov budget below two columns, Lanczos refinement skipped")
493 CALL timestop(handle)
494 RETURN
495 END IF
496 ! the budget bounds the block width: a wider block would append
497 ! past the end of vmat at its first seed call (nao - 2 caps nbmax
498 ! below the pending width on minimal bases). The pending set then
499 ! splits into narrower blocks, and no column is dropped
500 IF (nblock_e > nbmax - 2) THEN
501 nblock_e = max(nbmax - 2, 1)
502 single_block = nblock_e >= nmo_nc_loc
503 END IF
504
505 n_conv_cols = 0
506 max_res_norm = 0.0_dp
507 min_res_norm = huge(1.0_dp)
508 prefix_open = .true.
509 refined = .false.
510 any_truncated = .false.
511
512 block_loop: DO ib = 1, nmo_nc_loc, nblock_e
513 col_lo = nmo_converged + ib
514 col_hi = min(col_lo + nblock_e - 1, nmo_converged + nmo_nc_loc)
515 nmobt = col_hi - col_lo + 1
516 ws%ldone(1:nmobt) = .false.
517 nres = 0
518
519 ! ---------- seed block: the pending columns, purified and
520 ! orthonormalized into the working basis
521 CALL cp_cfm_to_cfm(c0, ws%cand_blk, nmobt, col_lo, 1)
522 CALL cp_cfm_vectorsnorm(ws%cand_blk, ws%nrm)
523 ws%rank_scale(1:nmobt) = ws%nrm(1:nmobt)
524 nbasis = 0
525 CALL purify_and_append(c0, col_lo - 1, ib == 1 .AND. skip_first_defl, ws, &
526 min(nmobt, nbmax), nbasis, nseed)
527 IF (nseed == 0) THEN
528 ! no seed survived the purification: no column of this block
529 ! converged, and the leading prefix cannot extend past it
530 prefix_open = .false.
531 any_truncated = .true.
532 cycle block_loop
533 END IF
534 nstep = nseed
535
536 ! ---------- expansion: extend the basis with the A-images of the
537 ! last batch until the budget is exhausted
538 DO WHILE (nbasis < nbmax .AND. nstep > 0)
539 CALL cp_cfm_gemm('N', 'N', nao, nstep, nao, z_one, ks, ws%vmat, z_zero, ws%hvmat, &
540 b_first_col=nbasis - nstep + 1, c_first_col=nbasis - nstep + 1)
541 CALL cp_cfm_to_cfm(ws%hvmat, ws%cand_blk, nstep, nbasis - nstep + 1, 1)
542 CALL cp_cfm_vectorsnorm(ws%cand_blk, ws%nrm)
543 ws%rank_scale(1:nstep) = ws%nrm(1:nstep)
544 nmob_c = min(nstep, nbmax - nbasis)
545 CALL purify_and_append(c0, col_lo - 1, .false., ws, nmob_c, nbasis, nseed)
546 nstep = nseed
547 END DO
548 ! the last batch has no successor: its A-images must still be
549 ! formed explicitly, or the projection reads the stale tail of
550 ! the reused product buffer and silently degrades the Ritz pairs
551 IF (nstep > 0) THEN
552 CALL cp_cfm_gemm('N', 'N', nao, nstep, nao, z_one, ks, ws%vmat, z_zero, ws%hvmat, &
553 b_first_col=nbasis - nstep + 1, c_first_col=nbasis - nstep + 1)
554 END IF
555
556 ! ---------- Rayleigh-Ritz: T = V^dag (A V) as a distributed
557 ! problem on a right-sized matrix, through the shared solver
558 ! stack
559 NULLIFY (fm_struct_tmp)
560 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nbasis, ncol_global=nbasis, &
561 para_env=para_env, context=blacs_env)
562 CALL cp_cfm_create(hsolve, matrix_struct=fm_struct_tmp, name="lan_h", set_zero=.true.)
563 CALL cp_cfm_create(esolve, matrix_struct=fm_struct_tmp, name="lan_e", set_zero=.true.)
564 CALL cp_fm_struct_release(fm_struct_tmp)
565 nres = min(nmobt, nbasis)
566 IF (nres < nmobt) any_truncated = .true.
567 ! one shared Rayleigh-Ritz pass per block, on the stored
568 ! A-images of the working basis: rotates the leading nres Ritz
569 ! vectors into c0(:, col_lo:col_lo+nres-1) and forms their exact
570 ! residual norms in ws%nrm
571 CALL rayleigh_ritz(ws%hvmat, ws%vmat, nbasis, nres, ws%theta, hsolve, esolve, &
572 ws%eval_scale, ws%cand_blk, col_lo, ws%nrm, c_dst=c0)
573 ws%pair_res(1:nres) = ws%nrm(1:nres)
574
575 ! ---------- write-back metadata: no pair-to-column identity ever
576 ! latches across calls, heevd re-sorts ascending. Columns beyond
577 ! nres keep their entry vectors and fall to the end-of-call
578 ! fallback
579 DO j = 1, nres
580 eval(col_lo + j - 1) = ws%theta(j)
581 ws%ldone(j) = ws%pair_res(j) < eps_col(col_lo + j - 1)
582 END DO
583 refined = .true.
584 CALL cp_cfm_release(hsolve)
585 CALL cp_cfm_release(esolve)
586
587 ! exit statistics: the residuals describe the state the columns
588 ! are left in, not the worst value seen during the call. The
589 ! converged count is the global leading converged run
590 DO j = 1, nres
591 max_res_norm = max(max_res_norm, ws%pair_res(j))
592 min_res_norm = min(min_res_norm, ws%pair_res(j))
593 END DO
594 IF (prefix_open) THEN
595 DO j = 1, nmobt
596 IF (.NOT. ws%ldone(j)) EXIT
597 n_conv_cols = n_conv_cols + 1
598 END DO
599 prefix_open = all(ws%ldone(1:nmobt))
600 END IF
601 END DO block_loop
602
603 need_suffix_rr = (.NOT. single_block) .OR. any_truncated
604
605 CALL timestop(handle)
606 END SUBROUTINE lanczos_refine
607
608! **************************************************************************************************
609!> \brief Purify a block of candidate directions and append the survivors to
610!> the working basis: projection passes against the working basis and
611!> the leading ndefl columns of c0, with the second pass decided by
612!> the DGKS norm-ratio test, modified Gram-Schmidt within the block,
613!> then a per-column rank safeguard relative to rank_scale,
614!> normalization and append. The count of appended columns is
615!> returned in napp. The kernel advances nbasis accordingly.
616!> \param c0 MOS holding the deflation columns
617!> \param ndefl number of leading c0 columns to deflate against
618!> \param skip_defl skip deflation when the seed block is already orthogonal
619!> to the deflation prefix (first block after a full-width RR)
620!> \param ws kernel workspace: cand_blk holds the candidate directions, nmob
621!> of them live. vmat is the working basis appended in place.
622!> rank_scale carries the per-column rank-safeguard scale, nrm the
623!> column norms, proj_coeff the projection coefficients, defl_coeff the
624!> deflation-projection coefficients and one_col the scratch column
625!> of the within-batch orthogonalization
626!> \param nmob number of live candidate columns
627!> \param nbasis number of basis columns on entry, advanced on exit
628!> \param napp number of appended columns
629! **************************************************************************************************
630 SUBROUTINE purify_and_append(c0, ndefl, skip_defl, ws, nmob, nbasis, napp)
631 TYPE(cp_cfm_type), INTENT(IN) :: c0
632 INTEGER, INTENT(IN) :: ndefl
633 LOGICAL, INTENT(IN) :: skip_defl
634 TYPE(lanczos_workspace_type), INTENT(INOUT) :: ws
635 INTEGER, INTENT(IN) :: nmob
636 INTEGER, INTENT(INOUT) :: nbasis
637 INTEGER, INTENT(OUT) :: napp
638
639 REAL(dp), PARAMETER :: eta_dgks = 0.70710678118654752_dp
640
641 COMPLEX(dp) :: col_scale1(1)
642 INTEGER :: icol, info, ipass, iqr, kept, nao
643 LOGICAL :: chol_ok, do_defl, do_purge
644
645 CALL cp_cfm_get_info(ws%cand_blk, nrow_global=nao)
646
647 ! batch purge: two passes of block gemms project the candidate set
648 ! against the working basis and the deflation prefix; the first seed
649 ! block after a full-width rotation skips it, later seed blocks must
650 ! deflate against the columns earlier blocks wrote
651 do_defl = (ndefl > 0) .AND. (.NOT. skip_defl)
652 do_purge = (nbasis > 0) .OR. do_defl
653 IF (do_purge) THEN
654 DO ipass = 1, 2
655 IF (nbasis > 0) THEN
656 CALL cp_cfm_gemm('C', 'N', nbasis, nmob, nao, z_one, ws%vmat, ws%cand_blk, z_zero, ws%proj_coeff)
657 CALL cp_cfm_gemm('N', 'N', nao, nmob, nbasis, z_mone, ws%vmat, ws%proj_coeff, z_one, ws%cand_blk)
658 END IF
659 IF (do_defl) THEN
660 CALL cp_cfm_gemm('C', 'N', ndefl, nmob, nao, z_one, c0, ws%cand_blk, z_zero, ws%defl_coeff)
661 CALL cp_cfm_gemm('N', 'N', nao, nmob, ndefl, z_mone, c0, ws%defl_coeff, z_one, ws%cand_blk)
662 END IF
663 CALL cp_cfm_vectorsnorm(ws%cand_blk, ws%nrm)
664 IF (ipass == 1) THEN
665 ! DGKS norm-ratio test (Daniel, Gragg, Kaufman and Stewart): a
666 ! first pass that left every candidate norm within eta_dgks of
667 ! its pre-purge norm already orthogonalized the batch to the
668 ! projected subspace to working precision
669 IF (all(ws%nrm(1:nmob) >= eta_dgks*ws%rank_scale(1:nmob))) EXIT
670 END IF
671 END DO
672 END IF
673
674 ! rank safeguard: once the Krylov space saturates the available
675 ! dimensions, the orthogonal complement is pure cancellation noise
676 ! and a residual of 1e-16 passes a plain positivity test
677 IF (all(ws%nrm(1:nmob) <= 1.0e-12_dp*ws%rank_scale(1:nmob))) THEN
678 napp = 0
679 RETURN
680 END IF
681
682 ! Path A: single-column fast path (norm guard already satisfied above)
683 IF (nmob == 1) THEN
684 ws%eval_scale(1) = cmplx(1.0_dp/ws%nrm(1), 0.0_dp, kind=dp)
685 IF (SIZE(ws%eval_scale) > 1) ws%eval_scale(2:) = z_zero
686 CALL cp_cfm_column_scale(ws%cand_blk, ws%eval_scale)
687 CALL cp_cfm_to_cfm(ws%cand_blk, ws%vmat, 1, 1, nbasis + 1)
688 napp = 1
689 nbasis = nbasis + 1
690 RETURN
691 END IF
692
693 ! Path B: healthy multi-column batch fast path via two-pass BLAS-3 CholeskyQR2
694 IF (all(ws%nrm(1:nmob) > 1.0e-12_dp*ws%rank_scale(1:nmob))) THEN
695 CALL cp_cfm_to_cfm(ws%cand_blk, ws%vmat, nmob, 1, nbasis + 1)
696 chol_ok = .true.
697 DO iqr = 1, 2
698 CALL cp_cfm_gemm('C', 'N', nmob, nmob, nao, z_one, ws%cand_blk, ws%cand_blk, &
699 z_zero, ws%batch_gram)
700 CALL cp_cfm_cholesky_decompose(ws%batch_gram, nmob, info)
701 IF (info /= 0) THEN
702 chol_ok = .false.
703 EXIT
704 END IF
705 CALL cp_cfm_triangular_multiply(ws%batch_gram, ws%cand_blk, side='R', &
706 invert_tr=.true., n_rows=nao, n_cols=nmob)
707 END DO
708 IF (chol_ok) THEN
709 CALL cp_cfm_to_cfm(ws%cand_blk, ws%vmat, nmob, 1, nbasis + 1)
710 napp = nmob
711 nbasis = nbasis + nmob
712 RETURN
713 END IF
714 CALL cp_cfm_to_cfm(ws%vmat, ws%cand_blk, nmob, nbasis + 1, 1)
715 END IF
716
717 ! Path C: rank-deficient / near-dependent fallback by two-pass CGS2
718 ! with per-column norm retirement
719 kept = 0
720 DO icol = 1, nmob
721 CALL cp_cfm_to_cfm(ws%cand_blk, ws%one_col, 1, icol, 1)
722 DO ipass = 1, 2
723 IF (kept > 0) THEN
724 CALL cp_cfm_gemm('C', 'N', kept, 1, nao, z_one, ws%cand_blk, &
725 ws%one_col, z_zero, ws%proj_coeff)
726 CALL cp_cfm_gemm('N', 'N', nao, 1, kept, z_mone, ws%cand_blk, &
727 ws%proj_coeff, z_one, ws%one_col)
728 END IF
729 END DO
730 CALL cp_cfm_vectorsnorm(ws%one_col, ws%nrm)
731 IF (ws%nrm(1) > 1.0e-12_dp*ws%rank_scale(icol)) THEN
732 col_scale1(1) = cmplx(1.0_dp/ws%nrm(1), 0.0_dp, kind=dp)
733 CALL cp_cfm_column_scale(ws%one_col, col_scale1)
734 kept = kept + 1
735 CALL cp_cfm_to_cfm(ws%one_col, ws%cand_blk, 1, 1, kept)
736 END IF
737 END DO
738 napp = kept
739 IF (napp > 0) CALL cp_cfm_to_cfm(ws%cand_blk, ws%vmat, napp, 1, nbasis + 1)
740 nbasis = nbasis + napp
741 END SUBROUTINE purify_and_append
742
743! **************************************************************************************************
744!> \brief One Rayleigh-Ritz pass on a precomputed basis pair: project
745!> the operator onto the basis, solve the small Hermitian
746!> problem, rotate the leading Ritz vectors into the target
747!> matrix window, and return their exact residual norms.
748!> \param abas A-images of the basis columns, A*B
749!> \param basis orthonormal basis B; updated in place when c_dst is absent
750!> \param nbas live basis width
751!> \param npairs number of leading Ritz pairs to write back and form residuals
752!> \param ritz_val eigenvalues of the projected problem, at least nbas
753!> \param small_t scratch holding the projected matrix on entry, right
754!> sized to nbas
755!> \param small_z scratch receiving the eigenvectors, right sized to nbas
756!> \param eval_scale complex scaling array spanning every global column
757!> of work_blk
758!> \param work_blk scratch receiving the rotated Ritz vectors and then
759!> the residual columns
760!> \param dst_col starting destination column in c_dst (or basis)
761!> \param res_norm residual norms, spans every global column of work_blk
762!> \param c_dst optional target matrix receiving the rotated Ritz vectors
763!> \param bas_col optional starting column of basis (defaults to 1)
764! **************************************************************************************************
765 SUBROUTINE rayleigh_ritz(abas, basis, nbas, npairs, ritz_val, small_t, small_z, &
766 eval_scale, work_blk, dst_col, res_norm, c_dst, bas_col)
767 TYPE(cp_cfm_type), INTENT(IN) :: abas
768 TYPE(cp_cfm_type), INTENT(INOUT) :: basis
769 INTEGER, INTENT(IN) :: nbas, npairs
770 REAL(dp), DIMENSION(:) :: ritz_val
771 TYPE(cp_cfm_type) :: small_t, small_z
772 COMPLEX(dp), DIMENSION(:) :: eval_scale
773 TYPE(cp_cfm_type) :: work_blk
774 INTEGER, INTENT(IN) :: dst_col
775 REAL(dp), DIMENSION(:) :: res_norm
776 TYPE(cp_cfm_type), INTENT(INOUT), OPTIONAL :: c_dst
777 INTEGER, INTENT(IN), OPTIONAL :: bas_col
778
779 INTEGER :: my_bas_col, nao, ncol_work
780
781 my_bas_col = 1
782 IF (PRESENT(bas_col)) my_bas_col = bas_col
783
784 CALL cp_cfm_get_info(work_blk, nrow_global=nao, ncol_global=ncol_work)
785
786 CALL cp_cfm_gemm('C', 'N', nbas, nbas, nao, z_one, basis, abas, z_zero, small_t, &
787 a_first_col=my_bas_col)
788 CALL cp_cfm_heevd(small_t, small_z, ritz_val(1:nbas))
789
790 CALL cp_cfm_gemm('N', 'N', nao, npairs, nbas, z_one, basis, small_z, z_zero, work_blk, &
791 a_first_col=my_bas_col)
792 IF (PRESENT(c_dst)) THEN
793 CALL cp_cfm_to_cfm(work_blk, c_dst, npairs, 1, dst_col)
794 ELSE
795 CALL cp_cfm_to_cfm(work_blk, basis, npairs, 1, dst_col)
796 END IF
797
798 eval_scale(1:npairs) = cmplx(-ritz_val(1:npairs), 0.0_dp, kind=dp)
799 IF (npairs < ncol_work) eval_scale(npairs + 1:ncol_work) = z_zero
800 CALL cp_cfm_column_scale(work_blk, eval_scale)
801 CALL cp_cfm_gemm('N', 'N', nao, npairs, nbas, z_one, abas, small_z, z_one, work_blk)
802 CALL cp_cfm_vectorsnorm(work_blk, res_norm)
803 END SUBROUTINE rayleigh_ritz
804
805! **************************************************************************************************
806!> \brief Create the kernel workspace at the worst-case widths of the run.
807!> The basis budget holds the larger of the NKRYLOV block budget
808!> and four times the widest single block, and every per-call
809!> clamp of the kernel stays below it. A single block covers
810!> every pending column only when NBLOCK spans them, so four
811!> times MIN(NBLOCK, nmo) bounds that regime. The candidate and
812!> Ritz widths hold the widest block a run can form
813!> \param ws workspace to create
814!> \param mo_struct structure of the channel MOS, nao x nmo
815!> \param ao_struct structure of the channel operators, nao x nao
816!> \param nkrylov number of block expansion steps of the block regime
817!> \param nblock number of columns refined jointly
818! **************************************************************************************************
819 SUBROUTINE lanczos_workspace_create(ws, mo_struct, ao_struct, nkrylov, nblock)
820 TYPE(lanczos_workspace_type), INTENT(OUT) :: ws
821 TYPE(cp_fm_struct_type), POINTER :: mo_struct, ao_struct
822 INTEGER, INTENT(IN) :: nkrylov, nblock
823
824 CHARACTER(LEN=*), PARAMETER :: routinen = 'lanczos_workspace_create'
825
826 INTEGER :: handle, nao, nbe, nmo, wdth
827 TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
828
829 CALL timeset(routinen, handle)
830 NULLIFY (fm_struct_tmp)
831
832 nao = ao_struct%nrow_global
833 nmo = mo_struct%ncol_global
834 nbe = min(max(nblock, 1), nmo)
835 ! a single block covering every pending column does not multiply
836 ! the budget by the block count
837 IF (max(nblock, 1) >= nmo) THEN
838 wdth = max(shared_budget_factor*nbe, nkrylov, nbe + 2)
839 ELSE
840 wdth = max(nkrylov*nbe, shared_budget_factor*nbe, nbe + 2)
841 END IF
842
843 CALL cp_cfm_create(ws%hmo, mo_struct, name="lan_hmo")
844 CALL cp_cfm_create(ws%rot_scr, mo_struct, name="lan_rot_scr")
845
846 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmo, ncol_global=nmo, &
847 para_env=mo_struct%para_env, context=mo_struct%context)
848 CALL cp_cfm_create(ws%mo_gram, matrix_struct=fm_struct_tmp, name="lan_mo_gram")
849 CALL cp_cfm_create(ws%evec, matrix_struct=fm_struct_tmp, name="lan_evec")
850 CALL cp_fm_struct_release(fm_struct_tmp)
851
852 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=wdth, &
853 para_env=ao_struct%para_env, context=ao_struct%context)
854 CALL cp_cfm_create(ws%vmat, matrix_struct=fm_struct_tmp, name="lan_v", set_zero=.true.)
855 CALL cp_cfm_create(ws%hvmat, matrix_struct=fm_struct_tmp, name="lan_hv", set_zero=.true.)
856 CALL cp_fm_struct_release(fm_struct_tmp)
857
858 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=nbe, &
859 para_env=ao_struct%para_env, context=ao_struct%context)
860 CALL cp_cfm_create(ws%cand_blk, matrix_struct=fm_struct_tmp, name="lan_r", set_zero=.true.)
861 CALL cp_fm_struct_release(fm_struct_tmp)
862
863 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nao, ncol_global=1, &
864 para_env=ao_struct%para_env, context=ao_struct%context)
865 CALL cp_cfm_create(ws%one_col, matrix_struct=fm_struct_tmp, name="lan_w", set_zero=.true.)
866 CALL cp_fm_struct_release(fm_struct_tmp)
867
868 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nbe, ncol_global=nbe, &
869 para_env=ao_struct%para_env, context=ao_struct%context)
870 CALL cp_cfm_create(ws%batch_gram, matrix_struct=fm_struct_tmp, name="lan_bgram", set_zero=.true.)
871 CALL cp_fm_struct_release(fm_struct_tmp)
872
873 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=wdth, ncol_global=nbe, &
874 para_env=ao_struct%para_env, context=ao_struct%context)
875 CALL cp_cfm_create(ws%proj_coeff, matrix_struct=fm_struct_tmp, name="lan_pcoeff", set_zero=.true.)
876 CALL cp_fm_struct_release(fm_struct_tmp)
877
878 CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nmo, ncol_global=nbe, &
879 para_env=mo_struct%para_env, context=mo_struct%context)
880 CALL cp_cfm_create(ws%defl_coeff, matrix_struct=fm_struct_tmp, name="lan_pcb", set_zero=.true.)
881 CALL cp_fm_struct_release(fm_struct_tmp)
882
883 ALLOCATE (ws%theta(wdth), ws%nrm(nbe), ws%rank_scale(nbe), ws%pair_res(nbe), ws%entry_res(nmo))
884 ALLOCATE (ws%ldone(nbe))
885 ALLOCATE (ws%eval_scale(max(nmo, nbe)))
886
887 CALL timestop(handle)
888 END SUBROUTINE lanczos_workspace_create
889
890! **************************************************************************************************
891!> \brief Release the kernel workspace. Safe on a workspace that was
892!> never created: the matrix components default to disassociated
893!> and the arrays to unallocated
894!> \param ws workspace to release
895! **************************************************************************************************
897 TYPE(lanczos_workspace_type), INTENT(INOUT) :: ws
898
899 CALL cp_cfm_release(ws%hmo)
900 CALL cp_cfm_release(ws%mo_gram)
901 CALL cp_cfm_release(ws%evec)
902 CALL cp_cfm_release(ws%rot_scr)
903 CALL cp_cfm_release(ws%vmat)
904 CALL cp_cfm_release(ws%hvmat)
905 CALL cp_cfm_release(ws%cand_blk)
906 CALL cp_cfm_release(ws%one_col)
907 CALL cp_cfm_release(ws%batch_gram)
908 CALL cp_cfm_release(ws%proj_coeff)
909 CALL cp_cfm_release(ws%defl_coeff)
910 IF (ALLOCATED(ws%theta)) DEALLOCATE (ws%theta)
911 IF (ALLOCATED(ws%nrm)) DEALLOCATE (ws%nrm)
912 IF (ALLOCATED(ws%rank_scale)) DEALLOCATE (ws%rank_scale)
913 IF (ALLOCATED(ws%pair_res)) DEALLOCATE (ws%pair_res)
914 IF (ALLOCATED(ws%entry_res)) DEALLOCATE (ws%entry_res)
915 IF (ALLOCATED(ws%ldone)) DEALLOCATE (ws%ldone)
916 IF (ALLOCATED(ws%eval_scale)) DEALLOCATE (ws%eval_scale)
917 END SUBROUTINE lanczos_workspace_release
918
919END MODULE qs_scf_lanczos_c
methods related to the blacs parallel environment
Basic linear algebra operations for complex full matrices.
subroutine, public cp_cfm_vectorsnorm(matrix, norm_array, squared)
find the norm of each column norm_{j}= sqrt( \sum_{i} A_{ij}*conjg(A_{ij}) ) Complex-valued mirror of...
subroutine, public cp_cfm_gemm(transa, transb, m, n, k, alpha, matrix_a, matrix_b, beta, matrix_c, a_first_col, a_first_row, b_first_col, b_first_row, c_first_col, c_first_row)
Performs one of the matrix-matrix operations: matrix_c = alpha * op1( matrix_a ) * op2( matrix_b ) + ...
subroutine, public cp_cfm_triangular_multiply(triangular_matrix, matrix_b, side, transa_tr, invert_tr, uplo_tr, unit_diag_tr, n_rows, n_cols, alpha)
Multiplies in place by a triangular matrix: matrix_b = alpha op(triangular_matrix) matrix_b or (if si...
subroutine, public cp_cfm_column_scale(matrix_a, scaling, first_col, source)
Scales columns of the full matrix by corresponding factors.
various cholesky decomposition related routines
subroutine, public cp_cfm_cholesky_decompose(matrix, n, info_out)
Used to replace a symmetric positive definite matrix M with its Cholesky decomposition U: M = U^T * U...
used for collecting diagonalization schemes available for cp_cfm_type
Definition cp_cfm_diag.F:14
subroutine, public cp_cfm_heevd(matrix, eigenvectors, eigenvalues)
Perform a diagonalisation of a complex matrix.
Definition cp_cfm_diag.F:94
Represents a complex full matrix distributed on many processors.
subroutine, public cp_cfm_release(matrix)
Releases a full matrix.
subroutine, public cp_cfm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
Creates a new full matrix with the given structure.
subroutine, public cp_cfm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, matrix_struct, para_env)
Returns information about a full matrix.
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Definition of mathematical constants and functions.
complex(kind=dp), parameter, public z_mone
complex(kind=dp), parameter, public z_one
complex(kind=dp), parameter, public z_zero
Interface to the message passing library MPI.
Complex block-Lanczos refinement kernel for k-point SCF diagonalization. Processes unconverged column...
subroutine, public lanczos_channel_end(c0, ws)
Defensive full-width Cholesky orthonormalization at the end of a channel's refinement sweeps,...
subroutine, public lanczos_workspace_release(ws)
Release the kernel workspace. Safe on a workspace that was never created: the matrix components defau...
subroutine, public lanczos_channel_begin(ks, c0, eval, eps_col, ws, max_res_norm, min_res_norm, nmo_conv, nmo_nc, check_moconv_only)
Entry preparation of one (k-point, spin) channel before its inner Lanczos sweeps: orthonormalizes the...
subroutine, public lanczos_sweep_suffix(ks, c0, eval, eps_col, nkrylov, nblock, first_sweep, need_suffix_rr, ws, max_res_norm, min_res_norm, nmo_conv, nmo_nc, step_refined, next_need_suffix_rr)
Run one inner Lanczos sweep on the unconverged suffix of c0. When the previous sweep ran in multi-blo...
subroutine, public lanczos_refinement_2v_c(ks, c0, eval, eps_col, nkrylov, nblock, ws, max_res_norm, min_res_norm, nmo_conv, nmo_nc, check_moconv_only)
Refine the non-converged columns of c0 on the standardized operator ks. The entry Rayleigh-Ritz pass ...
subroutine, public lanczos_workspace_create(ws, mo_struct, ao_struct, nkrylov, nblock)
Create the kernel workspace at the worst-case widths of the run. The basis budget holds the larger of...
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
Represent a complex full matrix.
keeps the information about the structure of a full matrix
stores all the informations relevant to an mpi environment
Caller-owned scratch of the refinement kernel: every matrix and array that the sweeps of one channel ...