(git:374b731)
Loading...
Searching...
No Matches
qs_scf_methods.F
Go to the documentation of this file.
1!--------------------------------------------------------------------------------------------------!
2! CP2K: A general program to perform molecular dynamics simulations !
3! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4! !
5! SPDX-License-Identifier: GPL-2.0-or-later !
6!--------------------------------------------------------------------------------------------------!
7
8! **************************************************************************************************
9!> \brief groups fairly general SCF methods, so that modules other than qs_scf can use them too
10!> split off from qs_scf to reduce dependencies
11!> \par History
12!> - Joost VandeVondele (03.2006)
13!> - combine_ks_matrices added (05.04.06,MK)
14!> - second ROKS scheme added (15.04.06,MK)
15!> - MO occupation management moved (29.08.2008,MK)
16!> - correct_mo_eigenvalues was moved from qs_mo_types;
17!> new subroutine shift_unocc_mos (03.2016, Sergey Chulkov)
18! **************************************************************************************************
20
35 USE cp_fm_types, ONLY: cp_fm_create,&
40 USE dbcsr_api, ONLY: &
41 dbcsr_add, dbcsr_desymmetrize, dbcsr_get_block_p, dbcsr_iterator_blocks_left, &
42 dbcsr_iterator_next_block, dbcsr_iterator_start, dbcsr_iterator_stop, dbcsr_iterator_type, &
43 dbcsr_multiply, dbcsr_p_type, dbcsr_type
48 USE kinds, ONLY: dp
52 USE qs_mo_types, ONLY: get_mo_set,&
54#include "./base/base_uses.f90"
55
56 IMPLICIT NONE
57
58 PRIVATE
59
60 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_scf_methods'
61 REAL(KIND=dp), PARAMETER :: ratio = 0.25_dp
62
63 PUBLIC :: combine_ks_matrices, &
64 cp_sm_mix, &
70
71 PRIVATE :: correct_mo_eigenvalues, shift_unocc_mos
72
74 MODULE PROCEDURE combine_ks_matrices_1, &
75 combine_ks_matrices_2
76 END INTERFACE combine_ks_matrices
77
78CONTAINS
79
80! **************************************************************************************************
81!> \brief perform (if requested) a density mixing
82!> \param p_mix_new New density matrices
83!> \param mixing_store ...
84!> \param rho_ao Density environment
85!> \param para_env ...
86!> \param iter_delta ...
87!> \param iter_count ...
88!> \param diis ...
89!> \param invert Invert mixing
90!> \par History
91!> 02.2003 created [fawzi]
92!> 08.2014 adapted for kpoints [JGH]
93!> \author fawzi
94! **************************************************************************************************
95 SUBROUTINE scf_env_density_mixing(p_mix_new, mixing_store, rho_ao, para_env, &
96 iter_delta, iter_count, diis, invert)
97 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: p_mix_new
98 TYPE(mixing_storage_type), POINTER :: mixing_store
99 TYPE(dbcsr_p_type), DIMENSION(:, :), POINTER :: rho_ao
100 TYPE(mp_para_env_type), POINTER :: para_env
101 REAL(kind=dp), INTENT(INOUT) :: iter_delta
102 INTEGER, INTENT(IN) :: iter_count
103 LOGICAL, INTENT(in), OPTIONAL :: diis, invert
104
105 CHARACTER(len=*), PARAMETER :: routinen = 'scf_env_density_mixing'
106
107 INTEGER :: handle, ic, ispin
108 LOGICAL :: my_diis, my_invert
109 REAL(kind=dp) :: my_p_mix, tmp
110
111 CALL timeset(routinen, handle)
112
113 my_diis = .false.
114 IF (PRESENT(diis)) my_diis = diis
115 my_invert = .false.
116 IF (PRESENT(invert)) my_invert = invert
117 my_p_mix = mixing_store%alpha
118 IF (my_diis .OR. iter_count < mixing_store%nskip_mixing) THEN
119 my_p_mix = 1.0_dp
120 END IF
121
122 iter_delta = 0.0_dp
123 cpassert(ASSOCIATED(p_mix_new))
124 DO ic = 1, SIZE(p_mix_new, 2)
125 DO ispin = 1, SIZE(p_mix_new, 1)
126 IF (my_invert) THEN
127 cpassert(my_p_mix /= 0.0_dp)
128 IF (my_p_mix /= 1.0_dp) THEN
129 CALL dbcsr_add(matrix_a=p_mix_new(ispin, ic)%matrix, &
130 alpha_scalar=1.0_dp/my_p_mix, &
131 matrix_b=rho_ao(ispin, ic)%matrix, &
132 beta_scalar=(my_p_mix - 1.0_dp)/my_p_mix)
133 END IF
134 ELSE
135 CALL cp_sm_mix(m1=p_mix_new(ispin, ic)%matrix, &
136 m2=rho_ao(ispin, ic)%matrix, &
137 p_mix=my_p_mix, &
138 delta=tmp, &
139 para_env=para_env)
140 iter_delta = max(iter_delta, tmp)
141 END IF
142 END DO
143 END DO
144
145 CALL timestop(handle)
146
147 END SUBROUTINE scf_env_density_mixing
148
149! **************************************************************************************************
150!> \brief Diagonalise the Kohn-Sham matrix to get a new set of MO eigen-
151!> vectors and MO eigenvalues. ks will be modified
152!> \param matrix_ks_fm ...
153!> \param mo_set ...
154!> \param ortho ...
155!> \param work ...
156!> \param cholesky_method ...
157!> \param do_level_shift activate the level shifting technique
158!> \param level_shift amount of shift applied (in a.u.)
159!> \param matrix_u_fm matrix U : S (overlap matrix) = U^T * U
160!> \param use_jacobi ...
161!> \date 01.05.2001
162!> \author Matthias Krack
163!> \version 1.0
164! **************************************************************************************************
165 SUBROUTINE eigensolver(matrix_ks_fm, mo_set, ortho, work, &
166 cholesky_method, do_level_shift, &
167 level_shift, matrix_u_fm, use_jacobi)
168 TYPE(cp_fm_type), INTENT(IN) :: matrix_ks_fm
169 TYPE(mo_set_type), INTENT(IN) :: mo_set
170 TYPE(cp_fm_type), INTENT(IN) :: ortho, work
171 INTEGER, INTENT(inout) :: cholesky_method
172 LOGICAL, INTENT(in) :: do_level_shift
173 REAL(kind=dp), INTENT(in) :: level_shift
174 TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: matrix_u_fm
175 LOGICAL, INTENT(in) :: use_jacobi
176
177 CHARACTER(len=*), PARAMETER :: routinen = 'eigensolver'
178
179 INTEGER :: handle, homo, nao, nmo
180 REAL(kind=dp), DIMENSION(:), POINTER :: mo_eigenvalues
181 TYPE(cp_fm_type), POINTER :: mo_coeff
182
183 CALL timeset(routinen, handle)
184
185 NULLIFY (mo_coeff)
186 NULLIFY (mo_eigenvalues)
187
188 ! Diagonalise the Kohn-Sham matrix
189
190 CALL get_mo_set(mo_set=mo_set, &
191 nao=nao, &
192 nmo=nmo, &
193 homo=homo, &
194 eigenvalues=mo_eigenvalues, &
195 mo_coeff=mo_coeff)
196
197 SELECT CASE (cholesky_method)
198 CASE (cholesky_reduce)
199 CALL cp_fm_cholesky_reduce(matrix_ks_fm, ortho)
200
201 IF (do_level_shift) &
202 CALL shift_unocc_mos(matrix_ks_fm=matrix_ks_fm, mo_coeff=mo_coeff, homo=homo, nmo=nmo, nao=nao, &
203 level_shift=level_shift, is_triangular=.true., matrix_u_fm=matrix_u_fm)
204
205 CALL choose_eigv_solver(matrix_ks_fm, work, mo_eigenvalues)
206 CALL cp_fm_cholesky_restore(work, nmo, ortho, mo_coeff, "SOLVE")
207 IF (do_level_shift) &
208 CALL correct_mo_eigenvalues(mo_eigenvalues, homo, nmo, level_shift)
209
210 CASE (cholesky_restore)
211 CALL cp_fm_upper_to_full(matrix_ks_fm, work)
212 CALL cp_fm_cholesky_restore(matrix_ks_fm, nao, ortho, work, &
213 "SOLVE", pos="RIGHT")
214 CALL cp_fm_cholesky_restore(work, nao, ortho, matrix_ks_fm, &
215 "SOLVE", pos="LEFT", transa="T")
216
217 IF (do_level_shift) &
218 CALL shift_unocc_mos(matrix_ks_fm=matrix_ks_fm, mo_coeff=mo_coeff, homo=homo, nmo=nmo, nao=nao, &
219 level_shift=level_shift, is_triangular=.true., matrix_u_fm=matrix_u_fm)
220
221 CALL choose_eigv_solver(matrix_ks_fm, work, mo_eigenvalues)
222 CALL cp_fm_cholesky_restore(work, nmo, ortho, mo_coeff, "SOLVE")
223
224 IF (do_level_shift) &
225 CALL correct_mo_eigenvalues(mo_eigenvalues, homo, nmo, level_shift)
226
227 CASE (cholesky_inverse)
228 CALL cp_fm_upper_to_full(matrix_ks_fm, work)
229
230 CALL cp_fm_triangular_multiply(ortho, matrix_ks_fm, side="R", transpose_tr=.false., &
231 invert_tr=.false., uplo_tr="U", n_rows=nao, n_cols=nao, alpha=1.0_dp)
232 CALL cp_fm_triangular_multiply(ortho, matrix_ks_fm, side="L", transpose_tr=.true., &
233 invert_tr=.false., uplo_tr="U", n_rows=nao, n_cols=nao, alpha=1.0_dp)
234
235 IF (do_level_shift) &
236 CALL shift_unocc_mos(matrix_ks_fm=matrix_ks_fm, mo_coeff=mo_coeff, homo=homo, nmo=nmo, nao=nao, &
237 level_shift=level_shift, is_triangular=.true., matrix_u_fm=matrix_u_fm)
238
239 CALL choose_eigv_solver(matrix_ks_fm, work, mo_eigenvalues)
240 CALL cp_fm_triangular_multiply(ortho, work, side="L", transpose_tr=.false., &
241 invert_tr=.false., uplo_tr="U", n_rows=nao, n_cols=nmo, alpha=1.0_dp)
242 CALL cp_fm_to_fm(work, mo_coeff, nmo, 1, 1)
243
244 IF (do_level_shift) &
245 CALL correct_mo_eigenvalues(mo_eigenvalues, homo, nmo, level_shift)
246
247 END SELECT
248
249 IF (use_jacobi) THEN
250 CALL cp_fm_to_fm(mo_coeff, ortho)
251 cholesky_method = cholesky_off
252 END IF
253
254 CALL timestop(handle)
255
256 END SUBROUTINE eigensolver
257
258! **************************************************************************************************
259!> \brief ...
260!> \param matrix_ks ...
261!> \param matrix_ks_fm ...
262!> \param mo_set ...
263!> \param ortho_dbcsr ...
264!> \param ksbuf1 ...
265!> \param ksbuf2 ...
266! **************************************************************************************************
267 SUBROUTINE eigensolver_dbcsr(matrix_ks, matrix_ks_fm, mo_set, ortho_dbcsr, ksbuf1, ksbuf2)
268 TYPE(dbcsr_type), POINTER :: matrix_ks
269 TYPE(cp_fm_type), INTENT(IN) :: matrix_ks_fm
270 TYPE(mo_set_type), INTENT(IN) :: mo_set
271 TYPE(dbcsr_type), POINTER :: ortho_dbcsr, ksbuf1, ksbuf2
272
273 CHARACTER(len=*), PARAMETER :: routinen = 'eigensolver_dbcsr'
274
275 INTEGER :: handle, nao, nmo
276 REAL(kind=dp), DIMENSION(:), POINTER :: mo_eigenvalues
277 TYPE(cp_fm_type) :: all_evecs, nmo_evecs
278 TYPE(cp_fm_type), POINTER :: mo_coeff
279
280 CALL timeset(routinen, handle)
281
282 NULLIFY (mo_coeff)
283 NULLIFY (mo_eigenvalues)
284
285 CALL get_mo_set(mo_set=mo_set, &
286 nao=nao, &
287 nmo=nmo, &
288 eigenvalues=mo_eigenvalues, &
289 mo_coeff=mo_coeff)
290
291! Reduce KS matrix
292 CALL dbcsr_desymmetrize(matrix_ks, ksbuf2)
293 CALL dbcsr_multiply('N', 'N', 1.0_dp, ksbuf2, ortho_dbcsr, 0.0_dp, ksbuf1)
294 CALL dbcsr_multiply('T', 'N', 1.0_dp, ortho_dbcsr, ksbuf1, 0.0_dp, ksbuf2)
295
296! Solve the eigenvalue problem
297 CALL copy_dbcsr_to_fm(ksbuf2, matrix_ks_fm)
298 CALL cp_fm_create(all_evecs, matrix_ks_fm%matrix_struct)
299 CALL choose_eigv_solver(matrix_ks_fm, all_evecs, mo_eigenvalues)
300
301 ! select first nmo eigenvectors
302 CALL cp_fm_create(nmo_evecs, mo_coeff%matrix_struct)
303 CALL cp_fm_to_fm(msource=all_evecs, mtarget=nmo_evecs, ncol=nmo)
304 CALL cp_fm_release(all_evecs)
305
306! Restore the eigenvector of the general eig. problem
307 CALL cp_dbcsr_sm_fm_multiply(ortho_dbcsr, nmo_evecs, mo_coeff, nmo)
308
309 CALL cp_fm_release(nmo_evecs)
310 CALL timestop(handle)
311
312 END SUBROUTINE eigensolver_dbcsr
313
314! **************************************************************************************************
315!> \brief ...
316!> \param matrix_ks_fm ...
317!> \param mo_set ...
318!> \param ortho ...
319!> \param work ...
320!> \param do_level_shift activate the level shifting technique
321!> \param level_shift amount of shift applied (in a.u.)
322!> \param matrix_u_fm matrix U : S (overlap matrix) = U^T * U
323!> \param use_jacobi ...
324!> \param jacobi_threshold ...
325! **************************************************************************************************
326 SUBROUTINE eigensolver_symm(matrix_ks_fm, mo_set, ortho, work, do_level_shift, &
327 level_shift, matrix_u_fm, use_jacobi, jacobi_threshold)
328 TYPE(cp_fm_type), INTENT(IN) :: matrix_ks_fm
329 TYPE(mo_set_type), INTENT(IN) :: mo_set
330 TYPE(cp_fm_type), INTENT(IN) :: ortho, work
331 LOGICAL, INTENT(IN) :: do_level_shift
332 REAL(kind=dp), INTENT(IN) :: level_shift
333 TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: matrix_u_fm
334 LOGICAL, INTENT(IN) :: use_jacobi
335 REAL(kind=dp), INTENT(IN) :: jacobi_threshold
336
337 CHARACTER(len=*), PARAMETER :: routinen = 'eigensolver_symm'
338
339 INTEGER :: handle, homo, nao, nelectron, nmo
340 REAL(kind=dp), DIMENSION(:), POINTER :: mo_eigenvalues
341 TYPE(cp_fm_type), POINTER :: mo_coeff
342
343 CALL timeset(routinen, handle)
344
345 NULLIFY (mo_coeff)
346 NULLIFY (mo_eigenvalues)
347
348 ! Diagonalise the Kohn-Sham matrix
349
350 CALL get_mo_set(mo_set=mo_set, &
351 nao=nao, &
352 nmo=nmo, &
353 homo=homo, &
354 nelectron=nelectron, &
355 eigenvalues=mo_eigenvalues, &
356 mo_coeff=mo_coeff)
357
358 IF (use_jacobi) THEN
359
360 CALL cp_fm_symm("L", "U", nao, homo, 1.0_dp, matrix_ks_fm, mo_coeff, 0.0_dp, work)
361 CALL parallel_gemm("T", "N", homo, nao - homo, nao, 1.0_dp, work, mo_coeff, &
362 0.0_dp, matrix_ks_fm, b_first_col=homo + 1, c_first_col=homo + 1)
363
364 ! Block Jacobi (pseudo-diagonalization, only one sweep)
365 CALL cp_fm_block_jacobi(matrix_ks_fm, mo_coeff, mo_eigenvalues, &
366 jacobi_threshold, homo + 1)
367
368 ELSE ! full S^(-1/2) has been computed
369
370 CALL cp_fm_symm("L", "U", nao, nao, 1.0_dp, matrix_ks_fm, ortho, 0.0_dp, work)
371 CALL parallel_gemm("T", "N", nao, nao, nao, 1.0_dp, ortho, work, 0.0_dp, matrix_ks_fm)
372
373 IF (do_level_shift) &
374 CALL shift_unocc_mos(matrix_ks_fm=matrix_ks_fm, mo_coeff=mo_coeff, homo=homo, nmo=nmo, nao=nao, &
375 level_shift=level_shift, is_triangular=.false., matrix_u_fm=matrix_u_fm)
376
377 CALL choose_eigv_solver(matrix_ks_fm, work, mo_eigenvalues)
378
379 CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, ortho, work, 0.0_dp, &
380 mo_coeff)
381
382 IF (do_level_shift) &
383 CALL correct_mo_eigenvalues(mo_eigenvalues, homo, nmo, level_shift)
384
385 END IF
386
387 CALL timestop(handle)
388
389 END SUBROUTINE eigensolver_symm
390
391! **************************************************************************************************
392
393! **************************************************************************************************
394!> \brief ...
395!> \param matrix_ks ...
396!> \param mo_set ...
397!> \param work ...
398!> \param do_level_shift activate the level shifting technique
399!> \param level_shift amount of shift applied (in a.u.)
400!> \param use_jacobi ...
401!> \param jacobi_threshold ...
402! **************************************************************************************************
403 SUBROUTINE eigensolver_simple(matrix_ks, mo_set, work, do_level_shift, &
404 level_shift, use_jacobi, jacobi_threshold)
405
406 TYPE(cp_fm_type), INTENT(IN) :: matrix_ks
407 TYPE(mo_set_type), INTENT(IN) :: mo_set
408 TYPE(cp_fm_type), INTENT(IN) :: work
409 LOGICAL, INTENT(IN) :: do_level_shift
410 REAL(kind=dp), INTENT(IN) :: level_shift
411 LOGICAL, INTENT(IN) :: use_jacobi
412 REAL(kind=dp), INTENT(IN) :: jacobi_threshold
413
414 CHARACTER(len=*), PARAMETER :: routinen = 'eigensolver_simple'
415
416 INTEGER :: handle, homo, nao, nelectron, nmo
417 REAL(kind=dp), DIMENSION(:), POINTER :: mo_eigenvalues
418 TYPE(cp_fm_type), POINTER :: mo_coeff
419
420 CALL timeset(routinen, handle)
421
422 NULLIFY (mo_coeff)
423 NULLIFY (mo_eigenvalues)
424
425 CALL get_mo_set(mo_set=mo_set, &
426 nao=nao, &
427 nmo=nmo, &
428 homo=homo, &
429 nelectron=nelectron, &
430 eigenvalues=mo_eigenvalues, &
431 mo_coeff=mo_coeff)
432
433 IF (do_level_shift) THEN
434 ! matrix_u_fm is simply an identity matrix, so we omit it here
435 CALL shift_unocc_mos(matrix_ks_fm=matrix_ks, mo_coeff=mo_coeff, homo=homo, nmo=nmo, nao=nao, &
436 level_shift=level_shift, is_triangular=.false.)
437 END IF
438
439 IF (use_jacobi) THEN
440 CALL cp_fm_symm("L", "U", nao, homo, 1.0_dp, matrix_ks, mo_coeff, 0.0_dp, work)
441 CALL parallel_gemm("T", "N", homo, nao - homo, nao, 1.0_dp, work, mo_coeff, &
442 0.0_dp, matrix_ks, b_first_col=homo + 1, c_first_col=homo + 1)
443 ! Block Jacobi (pseudo-diagonalization, only one sweep)
444 CALL cp_fm_block_jacobi(matrix_ks, mo_coeff, mo_eigenvalues, jacobi_threshold, homo + 1)
445 ELSE
446
447 CALL choose_eigv_solver(matrix_ks, work, mo_eigenvalues)
448
449 CALL cp_fm_to_fm(work, mo_coeff, nmo, 1, 1)
450
451 END IF
452
453 IF (do_level_shift) &
454 CALL correct_mo_eigenvalues(mo_eigenvalues, homo, nmo, level_shift)
455
456 CALL timestop(handle)
457
458 END SUBROUTINE eigensolver_simple
459
460! **************************************************************************************************
461!> \brief Perform a mixing of the given matrixes into the first matrix
462!> m1 = m2 + p_mix (m1-m2)
463!> \param m1 first (new) matrix, is modified
464!> \param m2 the second (old) matrix
465!> \param p_mix how much m1 is conserved (0: none, 1: all)
466!> \param delta maximum norm of m1-m2
467!> \param para_env ...
468!> \param m3 ...
469!> \par History
470!> 02.2003 rewamped [fawzi]
471!> \author fawzi
472!> \note
473!> if you what to store the result in m2 swap m1 and m2 an use
474!> (1-pmix) as pmix
475!> para_env should be removed (embedded in matrix)
476! **************************************************************************************************
477 SUBROUTINE cp_sm_mix(m1, m2, p_mix, delta, para_env, m3)
478
479 TYPE(dbcsr_type), POINTER :: m1, m2
480 REAL(kind=dp), INTENT(IN) :: p_mix
481 REAL(kind=dp), INTENT(OUT) :: delta
482 TYPE(mp_para_env_type), POINTER :: para_env
483 TYPE(dbcsr_type), OPTIONAL, POINTER :: m3
484
485 CHARACTER(len=*), PARAMETER :: routinen = 'cp_sm_mix'
486
487 INTEGER :: blk, handle, i, iblock_col, iblock_row, j
488 LOGICAL :: found
489 REAL(kind=dp), DIMENSION(:, :), POINTER :: p_delta_block, p_new_block, p_old_block
490 TYPE(dbcsr_iterator_type) :: iter
491
492 CALL timeset(routinen, handle)
493 delta = 0.0_dp
494
495 CALL dbcsr_iterator_start(iter, m1)
496 DO WHILE (dbcsr_iterator_blocks_left(iter))
497 CALL dbcsr_iterator_next_block(iter, iblock_row, iblock_col, p_new_block, blk)
498 CALL dbcsr_get_block_p(matrix=m2, row=iblock_row, col=iblock_col, &
499 block=p_old_block, found=found)
500 cpassert(ASSOCIATED(p_old_block))
501 IF (PRESENT(m3)) THEN
502 CALL dbcsr_get_block_p(matrix=m3, row=iblock_row, col=iblock_col, &
503 block=p_delta_block, found=found)
504 cpassert(ASSOCIATED(p_delta_block))
505
506 DO j = 1, SIZE(p_new_block, 2)
507 DO i = 1, SIZE(p_new_block, 1)
508 p_delta_block(i, j) = p_new_block(i, j) - p_old_block(i, j)
509 delta = max(delta, abs(p_delta_block(i, j)))
510 END DO
511 END DO
512 ELSE
513 DO j = 1, SIZE(p_new_block, 2)
514 DO i = 1, SIZE(p_new_block, 1)
515 p_new_block(i, j) = p_new_block(i, j) - p_old_block(i, j)
516 delta = max(delta, abs(p_new_block(i, j)))
517 p_new_block(i, j) = p_old_block(i, j) + p_mix*p_new_block(i, j)
518 END DO
519 END DO
520 END IF
521 END DO
522 CALL dbcsr_iterator_stop(iter)
523
524 CALL para_env%max(delta)
525
526 CALL timestop(handle)
527
528 END SUBROUTINE cp_sm_mix
529
530! **************************************************************************************************
531!> \brief ...
532!> \param ksa ...
533!> \param ksb ...
534!> \param occa ...
535!> \param occb ...
536!> \param roks_parameter ...
537! **************************************************************************************************
538 SUBROUTINE combine_ks_matrices_1(ksa, ksb, occa, occb, roks_parameter)
539
540 ! Combine the alpha and beta Kohn-Sham matrices during a restricted open
541 ! Kohn-Sham (ROKS) calculation
542 ! On input ksa and ksb contain the alpha and beta Kohn-Sham matrices,
543 ! respectively. occa and occb contain the corresponding MO occupation
544 ! numbers. On output the combined ROKS operator matrix is returned in ksa.
545
546 ! Literature: - C. C. J. Roothaan, Rev. Mod. Phys. 32, 179 (1960)
547 ! - M. F. Guest and V. R. Saunders, Mol. Phys. 28(3), 819 (1974)
548
549 TYPE(cp_fm_type), INTENT(IN) :: ksa, ksb
550 REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: occa, occb
551 REAL(KIND=dp), DIMENSION(0:2, 0:2, 1:2), &
552 INTENT(IN) :: roks_parameter
553
554 CHARACTER(LEN=*), PARAMETER :: routineN = 'combine_ks_matrices_1'
555
556 INTEGER :: handle, i, icol_global, icol_local, &
557 irow_global, irow_local, j, &
558 ncol_local, nrow_local
559 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
560 LOGICAL :: compatible_matrices
561 REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
562 POINTER :: fa, fb
563 TYPE(cp_fm_struct_type), POINTER :: ksa_struct, ksb_struct
564
565! -------------------------------------------------------------------------
566
567 CALL timeset(routinen, handle)
568
569 CALL cp_fm_get_info(matrix=ksa, &
570 matrix_struct=ksa_struct, &
571 nrow_local=nrow_local, &
572 ncol_local=ncol_local, &
573 row_indices=row_indices, &
574 col_indices=col_indices, &
575 local_data=fa)
576
577 CALL cp_fm_get_info(matrix=ksb, &
578 matrix_struct=ksb_struct, &
579 local_data=fb)
580
581 compatible_matrices = cp_fm_struct_equivalent(ksa_struct, ksb_struct)
582 cpassert(compatible_matrices)
583
584 IF (sum(occb) == 0.0_dp) fb = 0.0_dp
585
586 DO icol_local = 1, ncol_local
587 icol_global = col_indices(icol_local)
588 j = int(occa(icol_global)) + int(occb(icol_global))
589 DO irow_local = 1, nrow_local
590 irow_global = row_indices(irow_local)
591 i = int(occa(irow_global)) + int(occb(irow_global))
592 fa(irow_local, icol_local) = &
593 roks_parameter(i, j, 1)*fa(irow_local, icol_local) + &
594 roks_parameter(i, j, 2)*fb(irow_local, icol_local)
595 END DO
596 END DO
597
598 CALL timestop(handle)
599
600 END SUBROUTINE combine_ks_matrices_1
601
602! **************************************************************************************************
603!> \brief ...
604!> \param ksa ...
605!> \param ksb ...
606!> \param occa ...
607!> \param occb ...
608!> \param f ...
609!> \param nalpha ...
610!> \param nbeta ...
611! **************************************************************************************************
612 SUBROUTINE combine_ks_matrices_2(ksa, ksb, occa, occb, f, nalpha, nbeta)
613
614 ! Combine the alpha and beta Kohn-Sham matrices during a restricted open
615 ! Kohn-Sham (ROKS) calculation
616 ! On input ksa and ksb contain the alpha and beta Kohn-Sham matrices,
617 ! respectively. occa and occb contain the corresponding MO occupation
618 ! numbers. On output the combined ROKS operator matrix is returned in ksa.
619
620 ! Literature: - C. C. J. Roothaan, Rev. Mod. Phys. 32, 179 (1960)
621 ! - M. Filatov and S. Shaik, Chem. Phys. Lett. 288, 689 (1998)
622
623 TYPE(cp_fm_type), INTENT(IN) :: ksa, ksb
624 REAL(KIND=dp), DIMENSION(:), INTENT(IN) :: occa, occb
625 REAL(KIND=dp), INTENT(IN) :: f
626 INTEGER, INTENT(IN) :: nalpha, nbeta
627
628 CHARACTER(LEN=*), PARAMETER :: routineN = 'combine_ks_matrices_2'
629
630 INTEGER :: handle, icol_global, icol_local, &
631 irow_global, irow_local, ncol_local, &
632 nrow_local
633 INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
634 LOGICAL :: compatible_matrices
635 REAL(KIND=dp) :: beta, t1, t2, ta, tb
636 REAL(KIND=dp), CONTIGUOUS, DIMENSION(:, :), &
637 POINTER :: fa, fb
638 TYPE(cp_fm_struct_type), POINTER :: ksa_struct, ksb_struct
639
640! -------------------------------------------------------------------------
641
642 CALL timeset(routinen, handle)
643
644 CALL cp_fm_get_info(matrix=ksa, &
645 matrix_struct=ksa_struct, &
646 nrow_local=nrow_local, &
647 ncol_local=ncol_local, &
648 row_indices=row_indices, &
649 col_indices=col_indices, &
650 local_data=fa)
651
652 CALL cp_fm_get_info(matrix=ksb, &
653 matrix_struct=ksb_struct, &
654 local_data=fb)
655
656 compatible_matrices = cp_fm_struct_equivalent(ksa_struct, ksb_struct)
657 cpassert(compatible_matrices)
658
659 beta = 1.0_dp/(1.0_dp - f)
660
661 DO icol_local = 1, ncol_local
662
663 icol_global = col_indices(icol_local)
664
665 DO irow_local = 1, nrow_local
666
667 irow_global = row_indices(irow_local)
668
669 t1 = 0.5_dp*(fa(irow_local, icol_local) + fb(irow_local, icol_local))
670
671 IF ((0 < irow_global) .AND. (irow_global <= nbeta)) THEN
672 IF ((0 < icol_global) .AND. (icol_global <= nbeta)) THEN
673 ! closed-closed
674 fa(irow_local, icol_local) = t1
675 ELSE IF ((nbeta < icol_global) .AND. (icol_global <= nalpha)) THEN
676 ! closed-open
677 ta = 0.5_dp*(f - real(occa(icol_global), kind=dp))/f
678 tb = 0.5_dp*(f - real(occb(icol_global), kind=dp))/f
679 t2 = ta*fa(irow_local, icol_local) + tb*fb(irow_local, icol_local)
680 fa(irow_local, icol_local) = t1 + (beta - 1.0_dp)*t2
681 ELSE
682 ! closed-virtual
683 fa(irow_local, icol_local) = t1
684 END IF
685 ELSE IF ((nbeta < irow_global) .AND. (irow_global <= nalpha)) THEN
686 IF ((0 < irow_global) .AND. (irow_global <= nbeta)) THEN
687 ! open-closed
688 ta = 0.5_dp*(f - real(occa(irow_global), kind=dp))/f
689 tb = 0.5_dp*(f - real(occb(irow_global), kind=dp))/f
690 t2 = ta*fa(irow_local, icol_local) + tb*fb(irow_local, icol_local)
691 fa(irow_local, icol_local) = t1 + (beta - 1.0_dp)*t2
692 ELSE IF ((nbeta < icol_global) .AND. (icol_global <= nalpha)) THEN
693 ! open-open
694 ta = 0.5_dp*(f - real(occa(icol_global), kind=dp))/f
695 tb = 0.5_dp*(f - real(occb(icol_global), kind=dp))/f
696 t2 = ta*fa(irow_local, icol_local) + tb*fb(irow_local, icol_local)
697 IF (irow_global == icol_global) THEN
698 fa(irow_local, icol_local) = t1 - t2
699 ELSE
700 fa(irow_local, icol_local) = t1 - 0.5_dp*t2
701 END IF
702 ELSE
703 ! open-virtual
704 ta = 0.5_dp*(f - real(occa(irow_global), kind=dp))/f
705 tb = 0.5_dp*(f - real(occb(irow_global), kind=dp))/f
706 t2 = ta*fa(irow_local, icol_local) + tb*fb(irow_local, icol_local)
707 fa(irow_local, icol_local) = t1 - t2
708 END IF
709 ELSE
710 IF ((0 < irow_global) .AND. (irow_global < nbeta)) THEN
711 ! virtual-closed
712 fa(irow_local, icol_local) = t1
713 ELSE IF ((nbeta < icol_global) .AND. (icol_global <= nalpha)) THEN
714 ! virtual-open
715 ta = 0.5_dp*(f - real(occa(icol_global), kind=dp))/f
716 tb = 0.5_dp*(f - real(occb(icol_global), kind=dp))/f
717 t2 = ta*fa(irow_local, icol_local) + tb*fb(irow_local, icol_local)
718 fa(irow_local, icol_local) = t1 - t2
719 ELSE
720 ! virtual-virtual
721 fa(irow_local, icol_local) = t1
722 END IF
723 END IF
724
725 END DO
726 END DO
727
728 CALL timestop(handle)
729
730 END SUBROUTINE combine_ks_matrices_2
731
732! **************************************************************************************************
733!> \brief Correct MO eigenvalues after MO level shifting.
734!> \param mo_eigenvalues vector of eigenvalues
735!> \param homo index of the highest occupied molecular orbital
736!> \param nmo number of molecular orbitals
737!> \param level_shift amount of applied level shifting (in a.u.)
738!> \date 19.04.2002
739!> \par History
740!> - correct_mo_eigenvalues added (18.04.02,MK)
741!> - moved from module qs_mo_types, revised interface (03.2016, Sergey Chulkov)
742!> \author MK
743!> \version 1.0
744! **************************************************************************************************
745 PURE SUBROUTINE correct_mo_eigenvalues(mo_eigenvalues, homo, nmo, level_shift)
746
747 REAL(kind=dp), DIMENSION(:), INTENT(inout) :: mo_eigenvalues
748 INTEGER, INTENT(in) :: homo, nmo
749 REAL(kind=dp), INTENT(in) :: level_shift
750
751 INTEGER :: imo
752
753 DO imo = homo + 1, nmo
754 mo_eigenvalues(imo) = mo_eigenvalues(imo) - level_shift
755 END DO
756
757 END SUBROUTINE correct_mo_eigenvalues
758
759! **************************************************************************************************
760!> \brief Adjust the Kohn-Sham matrix by shifting the orbital energies of all
761!> unoccupied molecular orbitals
762!> \param matrix_ks_fm transformed Kohn-Sham matrix = U^{-1,T} * KS * U^{-1}
763!> \param mo_coeff matrix of molecular orbitals (C)
764!> \param homo number of occupied molecular orbitals
765!> \param nmo number of molecular orbitals
766!> \param nao number of atomic orbitals
767!> \param level_shift amount of shift applying (in a.u.)
768!> \param is_triangular indicates that matrix_u_fm contains an upper triangular matrix
769!> \param matrix_u_fm matrix U: S (overlap matrix) = U^T * U;
770!> assume an identity matrix if omitted
771!> \par History
772!> 03.2016 created [Sergey Chulkov]
773! **************************************************************************************************
774 SUBROUTINE shift_unocc_mos(matrix_ks_fm, mo_coeff, homo, nmo, nao, &
775 level_shift, is_triangular, matrix_u_fm)
776
777 TYPE(cp_fm_type), INTENT(IN) :: matrix_ks_fm, mo_coeff
778 INTEGER, INTENT(in) :: homo, nmo, nao
779 REAL(kind=dp), INTENT(in) :: level_shift
780 LOGICAL, INTENT(in) :: is_triangular
781 TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: matrix_u_fm
782
783 CHARACTER(len=*), PARAMETER :: routineN = 'shift_unocc_mos'
784
785 INTEGER :: handle
786 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: weights
787 TYPE(cp_fm_struct_type), POINTER :: ao_mo_fmstruct
788 TYPE(cp_fm_type) :: u_mo, u_mo_scaled
789
790 CALL timeset(routinen, handle)
791
792 NULLIFY (ao_mo_fmstruct)
793 CALL cp_fm_struct_create(ao_mo_fmstruct, nrow_global=nao, ncol_global=nmo, &
794 para_env=mo_coeff%matrix_struct%para_env, context=mo_coeff%matrix_struct%context)
795
796 CALL cp_fm_create(u_mo, ao_mo_fmstruct)
797 CALL cp_fm_create(u_mo_scaled, ao_mo_fmstruct)
798
799 CALL cp_fm_struct_release(ao_mo_fmstruct)
800
801 ! U * C
802 IF (PRESENT(matrix_u_fm)) THEN
803 IF (is_triangular) THEN
804 CALL cp_fm_to_fm(mo_coeff, u_mo)
805 CALL cp_fm_triangular_multiply(matrix_u_fm, u_mo, side="L", transpose_tr=.false., &
806 invert_tr=.false., uplo_tr="U", n_rows=nao, n_cols=nmo, alpha=1.0_dp)
807 ELSE
808 CALL parallel_gemm("N", "N", nao, nmo, nao, 1.0_dp, matrix_u_fm, mo_coeff, 0.0_dp, u_mo)
809 END IF
810 ELSE
811 ! assume U is an identity matrix
812 CALL cp_fm_to_fm(mo_coeff, u_mo)
813 END IF
814
815 CALL cp_fm_to_fm(u_mo, u_mo_scaled)
816
817 ! up-shift all unoccupied molecular orbitals by the amount of 'level_shift'
818 ! weight = diag(DELTA) = (0, ... 0, level_shift, ..., level_shift)
819 ! MO index : 1 .. homo homo+1 ... nmo
820 ALLOCATE (weights(nmo))
821 weights(1:homo) = 0.0_dp
822 weights(homo + 1:nmo) = level_shift
823 ! DELTA * U * C
824 ! DELTA is a diagonal matrix, so simply scale all the columns of (U * C) by weights(:)
825 CALL cp_fm_column_scale(u_mo_scaled, weights)
826 DEALLOCATE (weights)
827
828 ! NewKS = U^{-1,T} * KS * U^{-1} + (U * C) * DELTA * (U * C)^T
829 CALL parallel_gemm("N", "T", nao, nao, nmo, 1.0_dp, u_mo, u_mo_scaled, 1.0_dp, matrix_ks_fm)
830
831 CALL cp_fm_release(u_mo_scaled)
832 CALL cp_fm_release(u_mo)
833
834 CALL timestop(handle)
835
836 END SUBROUTINE shift_unocc_mos
837
838END MODULE qs_scf_methods
DBCSR operations in CP2K.
subroutine, public cp_dbcsr_sm_fm_multiply(matrix, fm_in, fm_out, ncol, alpha, beta)
multiply a dbcsr with a fm matrix
subroutine, public copy_dbcsr_to_fm(matrix, fm)
Copy a DBCSR matrix to a BLACS matrix.
basic linear algebra operations for full matrices
subroutine, public cp_fm_column_scale(matrixa, scaling)
scales column i of matrix a with scaling(i)
subroutine, public cp_fm_upper_to_full(matrix, work)
given an upper triangular matrix computes the corresponding full matrix
subroutine, public cp_fm_cholesky_restore(fm_matrix, neig, fm_matrixb, fm_matrixout, op, pos, transa)
...
subroutine, public cp_fm_symm(side, uplo, m, n, alpha, matrix_a, matrix_b, beta, matrix_c)
computes matrix_c = beta * matrix_c + alpha * matrix_a * matrix_b computes matrix_c = beta * matrix_c...
subroutine, public cp_fm_triangular_multiply(triangular_matrix, matrix_b, side, transpose_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...
various cholesky decomposition related routines
subroutine, public cp_fm_cholesky_reduce(matrix, matrixb, itype)
reduce a matrix pencil A,B to normal form B has to be cholesky decomposed with cp_fm_cholesky_decompo...
used for collecting some of the diagonalization schemes available for cp_fm_type. cp_fm_power also mo...
Definition cp_fm_diag.F:17
subroutine, public cp_fm_block_jacobi(matrix, eigenvectors, eigval, thresh, start_sec_block)
...
subroutine, public choose_eigv_solver(matrix, eigenvectors, eigenvalues, info)
Choose the Eigensolver depending on which library is available ELPA seems to be unstable for small sy...
Definition cp_fm_diag.F:208
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
logical function, public cp_fm_struct_equivalent(fmstruct1, fmstruct2)
returns true if the two matrix structures are equivalent, false otherwise.
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
subroutine, public cp_fm_create(matrix, matrix_struct, name, use_sp)
creates a new full matrix with the given structure
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public cholesky_restore
integer, parameter, public cholesky_off
integer, parameter, public cholesky_reduce
integer, parameter, public cholesky_inverse
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Interface to the message passing library MPI.
basic linear algebra operations for full matrixes
module that contains the definitions of the scf types
Definition and initialisation of the mo data type.
Definition qs_mo_types.F:22
subroutine, public get_mo_set(mo_set, maxocc, homo, lfomo, nao, nelectron, n_el_f, nmo, eigenvalues, occupation_numbers, mo_coeff, mo_coeff_b, uniform_occupation, kts, mu, flexible_electron_count)
Get the components of a MO set data structure.
groups fairly general SCF methods, so that modules other than qs_scf can use them too split off from ...
subroutine, public eigensolver_simple(matrix_ks, mo_set, work, do_level_shift, level_shift, use_jacobi, jacobi_threshold)
...
subroutine, public eigensolver_dbcsr(matrix_ks, matrix_ks_fm, mo_set, ortho_dbcsr, ksbuf1, ksbuf2)
...
subroutine, public scf_env_density_mixing(p_mix_new, mixing_store, rho_ao, para_env, iter_delta, iter_count, diis, invert)
perform (if requested) a density mixing
subroutine, public eigensolver_symm(matrix_ks_fm, mo_set, ortho, work, do_level_shift, level_shift, matrix_u_fm, use_jacobi, jacobi_threshold)
...
subroutine, public eigensolver(matrix_ks_fm, mo_set, ortho, work, cholesky_method, do_level_shift, level_shift, matrix_u_fm, use_jacobi)
Diagonalise the Kohn-Sham matrix to get a new set of MO eigen- vectors and MO eigenvalues....
subroutine, public cp_sm_mix(m1, m2, p_mix, delta, para_env, m3)
Perform a mixing of the given matrixes into the first matrix m1 = m2 + p_mix (m1-m2)
keeps the information about the structure of a full matrix
represent a full matrix
stores all the informations relevant to an mpi environment