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