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