Line data Source code
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 collects routines that perform operations directly related to MOs
10 : !> \note
11 : !> first version : most routines imported
12 : !> \author Joost VandeVondele (2003-08)
13 : ! **************************************************************************************************
14 : MODULE qs_mo_methods
15 : USE admm_types, ONLY: admm_type
16 : USE admm_utils, ONLY: admm_correct_for_eigenvalues,&
17 : admm_uncorrect_for_eigenvalues
18 : USE cp_blacs_env, ONLY: cp_blacs_env_type
19 : USE cp_dbcsr_api, ONLY: dbcsr_copy,&
20 : dbcsr_get_info,&
21 : dbcsr_init_p,&
22 : dbcsr_multiply,&
23 : dbcsr_p_type,&
24 : dbcsr_release_p,&
25 : dbcsr_type,&
26 : dbcsr_type_no_symmetry
27 : USE cp_dbcsr_diag, ONLY: cp_dbcsr_syevd,&
28 : cp_dbcsr_syevx
29 : USE cp_dbcsr_operations, ONLY: copy_dbcsr_to_fm,&
30 : copy_fm_to_dbcsr,&
31 : cp_dbcsr_m_by_n_from_template,&
32 : cp_dbcsr_sm_fm_multiply
33 : USE cp_fm_basic_linalg, ONLY: cp_fm_syrk,&
34 : cp_fm_triangular_multiply
35 : USE cp_fm_cholesky, ONLY: cp_fm_cholesky_decompose
36 : USE cp_fm_diag, ONLY: choose_eigv_solver,&
37 : cp_fm_power,&
38 : cp_fm_syevx
39 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
40 : cp_fm_struct_release,&
41 : cp_fm_struct_type
42 : USE cp_fm_types, ONLY: cp_fm_create,&
43 : cp_fm_get_info,&
44 : cp_fm_release,&
45 : cp_fm_to_fm,&
46 : cp_fm_type
47 : USE cp_log_handling, ONLY: cp_logger_get_default_io_unit
48 : USE kinds, ONLY: dp
49 : USE message_passing, ONLY: mp_para_env_type
50 : USE parallel_gemm_api, ONLY: parallel_gemm
51 : USE physcon, ONLY: evolt
52 : USE qs_mo_occupation, ONLY: set_mo_occupation
53 : USE qs_mo_types, ONLY: get_mo_set,&
54 : mo_set_type
55 : USE scf_control_types, ONLY: scf_control_type
56 : #include "./base/base_uses.f90"
57 :
58 : IMPLICIT NONE
59 : PRIVATE
60 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'qs_mo_methods'
61 :
62 : PUBLIC :: make_basis_simple, make_basis_cholesky, make_basis_sv, make_basis_sm, &
63 : make_basis_lowdin, calculate_subspace_eigenvalues, &
64 : calculate_orthonormality, calculate_magnitude, make_mo_eig
65 :
66 : INTERFACE calculate_subspace_eigenvalues
67 : MODULE PROCEDURE subspace_eigenvalues_ks_fm
68 : MODULE PROCEDURE subspace_eigenvalues_ks_dbcsr
69 : END INTERFACE
70 :
71 : INTERFACE make_basis_sv
72 : MODULE PROCEDURE make_basis_sv_fm
73 : MODULE PROCEDURE make_basis_sv_dbcsr
74 : END INTERFACE
75 :
76 : CONTAINS
77 :
78 : ! **************************************************************************************************
79 : !> \brief returns an S-orthonormal basis v (v^T S v ==1)
80 : !> \param vmatrix ...
81 : !> \param ncol ...
82 : !> \param matrix_s ...
83 : !> \par History
84 : !> 03.2006 created [Joost VandeVondele]
85 : ! **************************************************************************************************
86 32923 : SUBROUTINE make_basis_sm(vmatrix, ncol, matrix_s)
87 : TYPE(cp_fm_type), INTENT(IN) :: vmatrix
88 : INTEGER, INTENT(IN) :: ncol
89 : TYPE(dbcsr_type), POINTER :: matrix_s
90 :
91 : CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_sm'
92 : REAL(KIND=dp), PARAMETER :: rone = 1.0_dp, rzero = 0.0_dp
93 :
94 : INTEGER :: handle, n, ncol_global
95 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
96 : TYPE(cp_fm_type) :: overlap_vv, svmatrix
97 :
98 128 : IF (ncol .EQ. 0) RETURN
99 :
100 6559 : CALL timeset(routineN, handle)
101 :
102 6559 : CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
103 6559 : IF (ncol .GT. ncol_global) CPABORT("Wrong ncol value")
104 :
105 6559 : CALL cp_fm_create(svmatrix, vmatrix%matrix_struct, "SV")
106 6559 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, vmatrix, svmatrix, ncol)
107 :
108 6559 : NULLIFY (fm_struct_tmp)
109 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
110 : para_env=vmatrix%matrix_struct%para_env, &
111 6559 : context=vmatrix%matrix_struct%context)
112 6559 : CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
113 6559 : CALL cp_fm_struct_release(fm_struct_tmp)
114 :
115 6559 : CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, svmatrix, rzero, overlap_vv)
116 6559 : CALL cp_fm_cholesky_decompose(overlap_vv)
117 6559 : CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
118 :
119 6559 : CALL cp_fm_release(overlap_vv)
120 6559 : CALL cp_fm_release(svmatrix)
121 :
122 6559 : CALL timestop(handle)
123 :
124 6687 : END SUBROUTINE make_basis_sm
125 :
126 : ! **************************************************************************************************
127 : !> \brief returns an S-orthonormal basis v and the corresponding matrix S*v as well
128 : !> \param vmatrix ...
129 : !> \param ncol ...
130 : !> \param svmatrix ...
131 : !> \par History
132 : !> 03.2006 created [Joost VandeVondele]
133 : ! **************************************************************************************************
134 0 : SUBROUTINE make_basis_sv_fm(vmatrix, ncol, svmatrix)
135 :
136 : TYPE(cp_fm_type), INTENT(IN) :: vmatrix
137 : INTEGER, INTENT(IN) :: ncol
138 : TYPE(cp_fm_type), INTENT(IN) :: svmatrix
139 :
140 : CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_sv_fm'
141 : REAL(KIND=dp), PARAMETER :: rone = 1.0_dp, rzero = 0.0_dp
142 :
143 : INTEGER :: handle, n, ncol_global
144 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
145 : TYPE(cp_fm_type) :: overlap_vv
146 :
147 0 : IF (ncol .EQ. 0) RETURN
148 :
149 0 : CALL timeset(routineN, handle)
150 0 : NULLIFY (fm_struct_tmp)
151 :
152 0 : CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
153 0 : IF (ncol .GT. ncol_global) CPABORT("Wrong ncol value")
154 :
155 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
156 : para_env=vmatrix%matrix_struct%para_env, &
157 0 : context=vmatrix%matrix_struct%context)
158 0 : CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
159 0 : CALL cp_fm_struct_release(fm_struct_tmp)
160 :
161 0 : CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, svmatrix, rzero, overlap_vv)
162 0 : CALL cp_fm_cholesky_decompose(overlap_vv)
163 0 : CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
164 0 : CALL cp_fm_triangular_multiply(overlap_vv, svmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
165 :
166 0 : CALL cp_fm_release(overlap_vv)
167 :
168 0 : CALL timestop(handle)
169 :
170 0 : END SUBROUTINE make_basis_sv_fm
171 :
172 : ! **************************************************************************************************
173 : !> \brief ...
174 : !> \param vmatrix ...
175 : !> \param ncol ...
176 : !> \param svmatrix ...
177 : !> \param para_env ...
178 : !> \param blacs_env ...
179 : ! **************************************************************************************************
180 3280 : SUBROUTINE make_basis_sv_dbcsr(vmatrix, ncol, svmatrix, para_env, blacs_env)
181 :
182 : TYPE(dbcsr_type) :: vmatrix
183 : INTEGER, INTENT(IN) :: ncol
184 : TYPE(dbcsr_type) :: svmatrix
185 : TYPE(mp_para_env_type), POINTER :: para_env
186 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
187 :
188 : CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_sv_dbcsr'
189 : REAL(KIND=dp), PARAMETER :: rone = 1.0_dp, rzero = 0.0_dp
190 :
191 : INTEGER :: handle, n, ncol_global
192 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
193 : TYPE(cp_fm_type) :: fm_svmatrix, fm_vmatrix, overlap_vv
194 :
195 124 : IF (ncol .EQ. 0) RETURN
196 :
197 526 : CALL timeset(routineN, handle)
198 :
199 : !CALL cp_fm_get_info(matrix=vmatrix,nrow_global=n,ncol_global=ncol_global)
200 526 : CALL dbcsr_get_info(vmatrix, nfullrows_total=n, nfullcols_total=ncol_global)
201 526 : IF (ncol .GT. ncol_global) CPABORT("Wrong ncol value")
202 :
203 : CALL cp_fm_struct_create(fm_struct_tmp, context=blacs_env, nrow_global=ncol, &
204 526 : ncol_global=ncol, para_env=para_env)
205 526 : CALL cp_fm_create(overlap_vv, fm_struct_tmp, name="fm_overlap_vv")
206 526 : CALL cp_fm_struct_release(fm_struct_tmp)
207 :
208 : CALL cp_fm_struct_create(fm_struct_tmp, context=blacs_env, nrow_global=n, &
209 526 : ncol_global=ncol_global, para_env=para_env)
210 526 : CALL cp_fm_create(fm_vmatrix, fm_struct_tmp, name="fm_vmatrix")
211 526 : CALL cp_fm_create(fm_svmatrix, fm_struct_tmp, name="fm_svmatrix")
212 526 : CALL cp_fm_struct_release(fm_struct_tmp)
213 :
214 526 : CALL copy_dbcsr_to_fm(vmatrix, fm_vmatrix)
215 526 : CALL copy_dbcsr_to_fm(svmatrix, fm_svmatrix)
216 :
217 526 : CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, fm_vmatrix, fm_svmatrix, rzero, overlap_vv)
218 526 : CALL cp_fm_cholesky_decompose(overlap_vv)
219 526 : CALL cp_fm_triangular_multiply(overlap_vv, fm_vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
220 526 : CALL cp_fm_triangular_multiply(overlap_vv, fm_svmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
221 :
222 526 : CALL copy_fm_to_dbcsr(fm_vmatrix, vmatrix)
223 526 : CALL copy_fm_to_dbcsr(fm_svmatrix, svmatrix)
224 :
225 526 : CALL cp_fm_release(overlap_vv)
226 526 : CALL cp_fm_release(fm_vmatrix)
227 526 : CALL cp_fm_release(fm_svmatrix)
228 :
229 526 : CALL timestop(handle)
230 :
231 650 : END SUBROUTINE make_basis_sv_dbcsr
232 :
233 : ! **************************************************************************************************
234 : !> \brief return a set of S orthonormal vectors (C^T S C == 1) where
235 : !> the cholesky decomposed form of S is passed as an argument
236 : !> \param vmatrix ...
237 : !> \param ncol ...
238 : !> \param ortho cholesky decomposed S matrix
239 : !> \par History
240 : !> 03.2006 created [Joost VandeVondele]
241 : !> \note
242 : !> if the cholesky decomposed S matrix is not available
243 : !> use make_basis_sm since this is much faster than computing the
244 : !> cholesky decomposition of S
245 : ! **************************************************************************************************
246 22792 : SUBROUTINE make_basis_cholesky(vmatrix, ncol, ortho)
247 :
248 : TYPE(cp_fm_type), INTENT(IN) :: vmatrix
249 : INTEGER, INTENT(IN) :: ncol
250 : TYPE(cp_fm_type), INTENT(IN) :: ortho
251 :
252 : CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_cholesky'
253 : REAL(KIND=dp), PARAMETER :: rone = 1.0_dp, rzero = 0.0_dp
254 :
255 : INTEGER :: handle, n, ncol_global
256 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
257 : TYPE(cp_fm_type) :: overlap_vv
258 :
259 80 : IF (ncol .EQ. 0) RETURN
260 :
261 5678 : CALL timeset(routineN, handle)
262 5678 : NULLIFY (fm_struct_tmp)
263 :
264 5678 : CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
265 5678 : IF (ncol .GT. ncol_global) CPABORT("Wrong ncol value")
266 :
267 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
268 : para_env=vmatrix%matrix_struct%para_env, &
269 5678 : context=vmatrix%matrix_struct%context)
270 5678 : CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
271 5678 : CALL cp_fm_struct_release(fm_struct_tmp)
272 :
273 5678 : CALL cp_fm_triangular_multiply(ortho, vmatrix, n_cols=ncol)
274 5678 : CALL cp_fm_syrk('U', 'T', n, rone, vmatrix, 1, 1, rzero, overlap_vv)
275 5678 : CALL cp_fm_cholesky_decompose(overlap_vv)
276 5678 : CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
277 5678 : CALL cp_fm_triangular_multiply(ortho, vmatrix, n_cols=ncol, invert_tr=.TRUE.)
278 :
279 5678 : CALL cp_fm_release(overlap_vv)
280 :
281 5678 : CALL timestop(handle)
282 :
283 5758 : END SUBROUTINE make_basis_cholesky
284 :
285 : ! **************************************************************************************************
286 : !> \brief return a set of S orthonormal vectors (C^T S C == 1) where
287 : !> a Loedwin transformation is applied to keep the rotated vectors as close
288 : !> as possible to the original ones
289 : !> \param vmatrix ...
290 : !> \param ncol ...
291 : !> \param matrix_s ...
292 : !> \param
293 : !> \par History
294 : !> 05.2009 created [MI]
295 : !> \note
296 : ! **************************************************************************************************
297 2772 : SUBROUTINE make_basis_lowdin(vmatrix, ncol, matrix_s)
298 :
299 : TYPE(cp_fm_type), INTENT(IN) :: vmatrix
300 : INTEGER, INTENT(IN) :: ncol
301 : TYPE(dbcsr_type) :: matrix_s
302 :
303 : CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_lowdin'
304 : REAL(KIND=dp), PARAMETER :: rone = 1.0_dp, rzero = 0.0_dp
305 :
306 : INTEGER :: handle, n, ncol_global, ndep
307 : REAL(dp) :: threshold
308 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
309 : TYPE(cp_fm_type) :: csc, sc, work
310 :
311 0 : IF (ncol .EQ. 0) RETURN
312 :
313 462 : CALL timeset(routineN, handle)
314 462 : NULLIFY (fm_struct_tmp)
315 462 : threshold = 1.0E-7_dp
316 462 : CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
317 462 : IF (ncol .GT. ncol_global) CPABORT("Wrong ncol value")
318 :
319 462 : CALL cp_fm_create(sc, vmatrix%matrix_struct, "SC")
320 462 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, vmatrix, sc, ncol)
321 :
322 462 : NULLIFY (fm_struct_tmp)
323 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
324 : para_env=vmatrix%matrix_struct%para_env, &
325 462 : context=vmatrix%matrix_struct%context)
326 462 : CALL cp_fm_create(csc, fm_struct_tmp, "csc")
327 462 : CALL cp_fm_create(work, fm_struct_tmp, "work")
328 462 : CALL cp_fm_struct_release(fm_struct_tmp)
329 :
330 462 : CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, sc, rzero, csc)
331 462 : CALL cp_fm_power(csc, work, -0.5_dp, threshold, ndep)
332 462 : CALL parallel_gemm('N', 'N', n, ncol, ncol, rone, vmatrix, csc, rzero, sc)
333 462 : CALL cp_fm_to_fm(sc, vmatrix, ncol, 1, 1)
334 :
335 462 : CALL cp_fm_release(csc)
336 462 : CALL cp_fm_release(sc)
337 462 : CALL cp_fm_release(work)
338 :
339 462 : CALL timestop(handle)
340 :
341 462 : END SUBROUTINE make_basis_lowdin
342 :
343 : ! **************************************************************************************************
344 : !> \brief given a set of vectors, return an orthogonal (C^T C == 1) set
345 : !> spanning the same space (notice, only for cases where S==1)
346 : !> \param vmatrix ...
347 : !> \param ncol ...
348 : !> \par History
349 : !> 03.2006 created [Joost VandeVondele]
350 : ! **************************************************************************************************
351 14694 : SUBROUTINE make_basis_simple(vmatrix, ncol)
352 :
353 : TYPE(cp_fm_type), INTENT(IN) :: vmatrix
354 : INTEGER, INTENT(IN) :: ncol
355 :
356 : CHARACTER(LEN=*), PARAMETER :: routineN = 'make_basis_simple'
357 : REAL(KIND=dp), PARAMETER :: rone = 1.0_dp, rzero = 0.0_dp
358 :
359 : INTEGER :: handle, n, ncol_global
360 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
361 : TYPE(cp_fm_type) :: overlap_vv
362 :
363 70 : IF (ncol .EQ. 0) RETURN
364 :
365 3656 : CALL timeset(routineN, handle)
366 :
367 3656 : NULLIFY (fm_struct_tmp)
368 :
369 3656 : CALL cp_fm_get_info(matrix=vmatrix, nrow_global=n, ncol_global=ncol_global)
370 3656 : IF (ncol .GT. ncol_global) CPABORT("Wrong ncol value")
371 :
372 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol, ncol_global=ncol, &
373 : para_env=vmatrix%matrix_struct%para_env, &
374 3656 : context=vmatrix%matrix_struct%context)
375 3656 : CALL cp_fm_create(overlap_vv, fm_struct_tmp, "overlap_vv")
376 3656 : CALL cp_fm_struct_release(fm_struct_tmp)
377 :
378 3656 : CALL parallel_gemm('T', 'N', ncol, ncol, n, rone, vmatrix, vmatrix, rzero, overlap_vv)
379 3656 : CALL cp_fm_cholesky_decompose(overlap_vv)
380 3656 : CALL cp_fm_triangular_multiply(overlap_vv, vmatrix, n_cols=ncol, side='R', invert_tr=.TRUE.)
381 :
382 3656 : CALL cp_fm_release(overlap_vv)
383 :
384 3656 : CALL timestop(handle)
385 :
386 3726 : END SUBROUTINE make_basis_simple
387 :
388 : ! **************************************************************************************************
389 : !> \brief computes ritz values of a set of orbitals given a ks_matrix
390 : !> rotates the orbitals into eigenstates depending on do_rotation
391 : !> writes the evals to the screen depending on ionode/scr
392 : !> \param orbitals S-orthonormal orbitals
393 : !> \param ks_matrix Kohn-Sham matrix
394 : !> \param evals_arg optional, filled with the evals
395 : !> \param ionode , scr if present write to unit scr where ionode
396 : !> \param scr ...
397 : !> \param do_rotation optional rotate orbitals (default=.TRUE.)
398 : !> note that rotating the orbitals is slower
399 : !> \param co_rotate an optional set of orbitals rotated by the same rotation matrix
400 : !> \param co_rotate_dbcsr ...
401 : !> \par History
402 : !> 08.2004 documented and added do_rotation [Joost VandeVondele]
403 : !> 09.2008 only compute eigenvalues if rotation is not needed
404 : ! **************************************************************************************************
405 1002 : SUBROUTINE subspace_eigenvalues_ks_fm(orbitals, ks_matrix, evals_arg, ionode, scr, &
406 : do_rotation, co_rotate, co_rotate_dbcsr)
407 :
408 : TYPE(cp_fm_type), INTENT(IN) :: orbitals
409 : TYPE(dbcsr_type), POINTER :: ks_matrix
410 : REAL(KIND=dp), DIMENSION(:), OPTIONAL :: evals_arg
411 : LOGICAL, INTENT(IN), OPTIONAL :: ionode
412 : INTEGER, INTENT(IN), OPTIONAL :: scr
413 : LOGICAL, INTENT(IN), OPTIONAL :: do_rotation
414 : TYPE(cp_fm_type), INTENT(IN), OPTIONAL :: co_rotate
415 : TYPE(dbcsr_type), OPTIONAL, POINTER :: co_rotate_dbcsr
416 :
417 : CHARACTER(len=*), PARAMETER :: routineN = 'subspace_eigenvalues_ks_fm'
418 :
419 : INTEGER :: handle, i, j, n, ncol_global, nrow_global
420 : LOGICAL :: compute_evecs, do_rotation_local
421 1002 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: evals
422 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
423 : TYPE(cp_fm_type) :: e_vectors, h_block, weighted_vectors, &
424 : weighted_vectors2
425 :
426 1002 : CALL timeset(routineN, handle)
427 :
428 1002 : do_rotation_local = .TRUE.
429 1002 : IF (PRESENT(do_rotation)) do_rotation_local = do_rotation
430 :
431 1002 : NULLIFY (fm_struct_tmp)
432 : CALL cp_fm_get_info(matrix=orbitals, &
433 : ncol_global=ncol_global, &
434 1002 : nrow_global=nrow_global)
435 :
436 : IF (do_rotation_local) THEN
437 : compute_evecs = .TRUE.
438 : ELSE
439 : ! this would be the logical choice if syevx computing only evals were faster than syevd computing evecs and evals.
440 : compute_evecs = .FALSE.
441 : ! this is not the case, so lets compute evecs always
442 : compute_evecs = .TRUE.
443 : END IF
444 :
445 1002 : IF (ncol_global .GT. 0) THEN
446 :
447 2634 : ALLOCATE (evals(ncol_global))
448 :
449 878 : CALL cp_fm_create(weighted_vectors, orbitals%matrix_struct, "weighted_vectors")
450 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=ncol_global, ncol_global=ncol_global, &
451 : para_env=orbitals%matrix_struct%para_env, &
452 878 : context=orbitals%matrix_struct%context)
453 878 : CALL cp_fm_create(h_block, fm_struct_tmp, name="h block")
454 878 : IF (compute_evecs) THEN
455 878 : CALL cp_fm_create(e_vectors, fm_struct_tmp, name="e vectors")
456 : END IF
457 878 : CALL cp_fm_struct_release(fm_struct_tmp)
458 :
459 : ! h subblock and diag
460 878 : CALL cp_dbcsr_sm_fm_multiply(ks_matrix, orbitals, weighted_vectors, ncol_global)
461 :
462 : CALL parallel_gemm('T', 'N', ncol_global, ncol_global, nrow_global, 1.0_dp, &
463 878 : orbitals, weighted_vectors, 0.0_dp, h_block)
464 :
465 : ! if eigenvectors are required, go for syevd, otherwise only compute eigenvalues
466 : IF (compute_evecs) THEN
467 878 : CALL choose_eigv_solver(h_block, e_vectors, evals)
468 : ELSE
469 : CALL cp_fm_syevx(h_block, eigenvalues=evals)
470 : END IF
471 :
472 : ! rotate the orbitals
473 878 : IF (do_rotation_local) THEN
474 : CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
475 594 : orbitals, e_vectors, 0.0_dp, weighted_vectors)
476 594 : CALL cp_fm_to_fm(weighted_vectors, orbitals)
477 594 : IF (PRESENT(co_rotate)) THEN
478 : CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
479 0 : co_rotate, e_vectors, 0.0_dp, weighted_vectors)
480 0 : CALL cp_fm_to_fm(weighted_vectors, co_rotate)
481 : END IF
482 594 : IF (PRESENT(co_rotate_dbcsr)) THEN
483 136 : IF (ASSOCIATED(co_rotate_dbcsr)) THEN
484 136 : CALL cp_fm_create(weighted_vectors2, orbitals%matrix_struct, "weighted_vectors")
485 136 : CALL copy_dbcsr_to_fm(co_rotate_dbcsr, weighted_vectors2)
486 : CALL parallel_gemm('N', 'N', nrow_global, ncol_global, ncol_global, 1.0_dp, &
487 136 : weighted_vectors2, e_vectors, 0.0_dp, weighted_vectors)
488 136 : CALL copy_fm_to_dbcsr(weighted_vectors, co_rotate_dbcsr)
489 136 : CALL cp_fm_release(weighted_vectors2)
490 : END IF
491 : END IF
492 : END IF
493 :
494 : ! give output
495 878 : IF (PRESENT(evals_arg)) THEN
496 846 : n = MIN(SIZE(evals_arg), SIZE(evals))
497 7508 : evals_arg(1:n) = evals(1:n)
498 : END IF
499 :
500 878 : IF (PRESENT(ionode) .OR. PRESENT(scr)) THEN
501 196 : IF (.NOT. PRESENT(ionode)) CPABORT("IONODE?")
502 196 : IF (.NOT. PRESENT(scr)) CPABORT("SCR?")
503 196 : IF (ionode) THEN
504 248 : DO i = 1, ncol_global, 4
505 150 : j = MIN(3, ncol_global - i)
506 98 : SELECT CASE (j)
507 : CASE (3)
508 111 : WRITE (scr, '(1X,4F16.8)') evals(i:i + j)
509 : CASE (2)
510 2 : WRITE (scr, '(1X,3F16.8)') evals(i:i + j)
511 : CASE (1)
512 8 : WRITE (scr, '(1X,2F16.8)') evals(i:i + j)
513 : CASE (0)
514 150 : WRITE (scr, '(1X,1F16.8)') evals(i:i + j)
515 : END SELECT
516 : END DO
517 : END IF
518 : END IF
519 :
520 878 : CALL cp_fm_release(weighted_vectors)
521 878 : CALL cp_fm_release(h_block)
522 : IF (compute_evecs) THEN
523 878 : CALL cp_fm_release(e_vectors)
524 : END IF
525 :
526 2634 : DEALLOCATE (evals)
527 :
528 : END IF
529 :
530 1002 : CALL timestop(handle)
531 :
532 2004 : END SUBROUTINE subspace_eigenvalues_ks_fm
533 :
534 : ! **************************************************************************************************
535 : !> \brief ...
536 : !> \param orbitals ...
537 : !> \param ks_matrix ...
538 : !> \param evals_arg ...
539 : !> \param ionode ...
540 : !> \param scr ...
541 : !> \param do_rotation ...
542 : !> \param co_rotate ...
543 : !> \param para_env ...
544 : !> \param blacs_env ...
545 : ! **************************************************************************************************
546 5434 : SUBROUTINE subspace_eigenvalues_ks_dbcsr(orbitals, ks_matrix, evals_arg, ionode, scr, &
547 : do_rotation, co_rotate, para_env, blacs_env)
548 :
549 : TYPE(dbcsr_type), POINTER :: orbitals, ks_matrix
550 : REAL(KIND=dp), DIMENSION(:), OPTIONAL :: evals_arg
551 : LOGICAL, INTENT(IN), OPTIONAL :: ionode
552 : INTEGER, INTENT(IN), OPTIONAL :: scr
553 : LOGICAL, INTENT(IN), OPTIONAL :: do_rotation
554 : TYPE(dbcsr_type), OPTIONAL, POINTER :: co_rotate
555 : TYPE(mp_para_env_type), POINTER :: para_env
556 : TYPE(cp_blacs_env_type), POINTER :: blacs_env
557 :
558 : CHARACTER(len=*), PARAMETER :: routineN = 'subspace_eigenvalues_ks_dbcsr'
559 :
560 : INTEGER :: handle, i, j, ncol_global, nrow_global
561 : LOGICAL :: compute_evecs, do_rotation_local
562 5434 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: evals
563 : TYPE(dbcsr_type), POINTER :: e_vectors, h_block, weighted_vectors
564 :
565 5434 : CALL timeset(routineN, handle)
566 :
567 5434 : do_rotation_local = .TRUE.
568 5434 : IF (PRESENT(do_rotation)) do_rotation_local = do_rotation
569 :
570 5434 : NULLIFY (e_vectors, h_block, weighted_vectors)
571 :
572 : CALL dbcsr_get_info(matrix=orbitals, &
573 : nfullcols_total=ncol_global, &
574 5434 : nfullrows_total=nrow_global)
575 :
576 : IF (do_rotation_local) THEN
577 : compute_evecs = .TRUE.
578 : ELSE
579 : ! this would be the logical choice if syevx computing only evals were faster than syevd computing evecs and evals.
580 : compute_evecs = .FALSE.
581 : ! this is not the case, so lets compute evecs always
582 : compute_evecs = .TRUE.
583 : END IF
584 :
585 5434 : IF (ncol_global .GT. 0) THEN
586 :
587 15690 : ALLOCATE (evals(ncol_global))
588 :
589 5230 : CALL dbcsr_init_p(weighted_vectors)
590 5230 : CALL dbcsr_copy(weighted_vectors, orbitals, name="weighted_vectors")
591 :
592 5230 : CALL dbcsr_init_p(h_block)
593 : CALL cp_dbcsr_m_by_n_from_template(h_block, template=orbitals, m=ncol_global, n=ncol_global, &
594 5230 : sym=dbcsr_type_no_symmetry)
595 :
596 : !!!!!!!!!!!!!!XXXXXXXXXXXXXXXXXXX!!!!!!!!!!!!!
597 : IF (compute_evecs) THEN
598 5230 : CALL dbcsr_init_p(e_vectors)
599 : CALL cp_dbcsr_m_by_n_from_template(e_vectors, template=orbitals, m=ncol_global, n=ncol_global, &
600 5230 : sym=dbcsr_type_no_symmetry)
601 : END IF
602 :
603 : ! h subblock and diag
604 : CALL dbcsr_multiply('N', 'N', 1.0_dp, ks_matrix, orbitals, &
605 5230 : 0.0_dp, weighted_vectors)
606 : !CALL cp_dbcsr_sm_fm_multiply(ks_matrix,orbitals,weighted_vectors, ncol_global)
607 :
608 5230 : CALL dbcsr_multiply('T', 'N', 1.0_dp, orbitals, weighted_vectors, 0.0_dp, h_block)
609 : !CALL parallel_gemm('T','N',ncol_global,ncol_global,nrow_global,1.0_dp, &
610 : ! orbitals,weighted_vectors,0.0_dp,h_block)
611 :
612 : ! if eigenvectors are required, go for syevd, otherwise only compute eigenvalues
613 : IF (compute_evecs) THEN
614 5230 : CALL cp_dbcsr_syevd(h_block, e_vectors, evals, para_env=para_env, blacs_env=blacs_env)
615 : ELSE
616 : CALL cp_dbcsr_syevx(h_block, eigenvalues=evals, para_env=para_env, blacs_env=blacs_env)
617 : END IF
618 :
619 : ! rotate the orbitals
620 5230 : IF (do_rotation_local) THEN
621 2556 : CALL dbcsr_multiply('N', 'N', 1.0_dp, orbitals, e_vectors, 0.0_dp, weighted_vectors)
622 : !CALL parallel_gemm('N','N',nrow_global,ncol_global,ncol_global,1.0_dp, &
623 : ! orbitals,e_vectors,0.0_dp,weighted_vectors)
624 2556 : CALL dbcsr_copy(orbitals, weighted_vectors)
625 : !CALL cp_fm_to_fm(weighted_vectors,orbitals)
626 2556 : IF (PRESENT(co_rotate)) THEN
627 2538 : IF (ASSOCIATED(co_rotate)) THEN
628 2538 : CALL dbcsr_multiply('N', 'N', 1.0_dp, co_rotate, e_vectors, 0.0_dp, weighted_vectors)
629 : !CALL parallel_gemm('N','N',nrow_global,ncol_global,ncol_global,1.0_dp, &
630 : ! co_rotate,e_vectors,0.0_dp,weighted_vectors)
631 2538 : CALL dbcsr_copy(co_rotate, weighted_vectors)
632 : !CALL cp_fm_to_fm(weighted_vectors,co_rotate)
633 : END IF
634 : END IF
635 : END IF
636 :
637 : ! give output
638 5230 : IF (PRESENT(evals_arg)) THEN
639 14702 : evals_arg(:) = evals(:)
640 : END IF
641 :
642 5230 : IF (PRESENT(ionode) .OR. PRESENT(scr)) THEN
643 0 : IF (.NOT. PRESENT(ionode)) CPABORT("IONODE?")
644 0 : IF (.NOT. PRESENT(scr)) CPABORT("SCR?")
645 0 : IF (ionode) THEN
646 0 : DO i = 1, ncol_global, 4
647 0 : j = MIN(3, ncol_global - i)
648 0 : SELECT CASE (j)
649 : CASE (3)
650 0 : WRITE (scr, '(1X,4F16.8)') evals(i:i + j)
651 : CASE (2)
652 0 : WRITE (scr, '(1X,3F16.8)') evals(i:i + j)
653 : CASE (1)
654 0 : WRITE (scr, '(1X,2F16.8)') evals(i:i + j)
655 : CASE (0)
656 0 : WRITE (scr, '(1X,1F16.8)') evals(i:i + j)
657 : END SELECT
658 : END DO
659 : END IF
660 : END IF
661 :
662 5230 : CALL dbcsr_release_p(weighted_vectors)
663 5230 : CALL dbcsr_release_p(h_block)
664 : IF (compute_evecs) THEN
665 5230 : CALL dbcsr_release_p(e_vectors)
666 : END IF
667 :
668 5230 : DEALLOCATE (evals)
669 :
670 : END IF
671 :
672 5434 : CALL timestop(handle)
673 :
674 5434 : END SUBROUTINE subspace_eigenvalues_ks_dbcsr
675 :
676 : ! computes the effective orthonormality of a set of mos given an s-matrix
677 : ! orthonormality is the max deviation from unity of the C^T S C
678 : ! **************************************************************************************************
679 : !> \brief ...
680 : !> \param orthonormality ...
681 : !> \param mo_array ...
682 : !> \param matrix_s ...
683 : ! **************************************************************************************************
684 866 : SUBROUTINE calculate_orthonormality(orthonormality, mo_array, matrix_s)
685 : REAL(KIND=dp) :: orthonormality
686 : TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mo_array
687 : TYPE(dbcsr_type), OPTIONAL, POINTER :: matrix_s
688 :
689 : CHARACTER(len=*), PARAMETER :: routineN = 'calculate_orthonormality'
690 :
691 : INTEGER :: handle, i, ispin, j, k, n, ncol_local, &
692 : nrow_local, nspin
693 866 : INTEGER, DIMENSION(:), POINTER :: col_indices, row_indices
694 : REAL(KIND=dp) :: alpha, max_alpha
695 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
696 : TYPE(cp_fm_type) :: overlap, svec
697 :
698 866 : NULLIFY (tmp_fm_struct)
699 :
700 866 : CALL timeset(routineN, handle)
701 :
702 866 : nspin = SIZE(mo_array)
703 866 : max_alpha = 0.0_dp
704 :
705 1744 : DO ispin = 1, nspin
706 878 : IF (PRESENT(matrix_s)) THEN
707 : ! get S*C
708 820 : CALL cp_fm_create(svec, mo_array(ispin)%mo_coeff%matrix_struct)
709 : CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
710 820 : nrow_global=n, ncol_global=k)
711 : CALL cp_dbcsr_sm_fm_multiply(matrix_s, mo_array(ispin)%mo_coeff, &
712 820 : svec, k)
713 : ! get C^T (S*C)
714 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
715 : para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
716 820 : context=mo_array(ispin)%mo_coeff%matrix_struct%context)
717 820 : CALL cp_fm_create(overlap, tmp_fm_struct)
718 820 : CALL cp_fm_struct_release(tmp_fm_struct)
719 : CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
720 820 : svec, 0.0_dp, overlap)
721 820 : CALL cp_fm_release(svec)
722 : ELSE
723 : ! orthogonal basis C^T C
724 : CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
725 58 : nrow_global=n, ncol_global=k)
726 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
727 : para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
728 58 : context=mo_array(ispin)%mo_coeff%matrix_struct%context)
729 58 : CALL cp_fm_create(overlap, tmp_fm_struct)
730 58 : CALL cp_fm_struct_release(tmp_fm_struct)
731 : CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
732 58 : mo_array(ispin)%mo_coeff, 0.0_dp, overlap)
733 : END IF
734 : CALL cp_fm_get_info(overlap, nrow_local=nrow_local, ncol_local=ncol_local, &
735 878 : row_indices=row_indices, col_indices=col_indices)
736 5025 : DO i = 1, nrow_local
737 324276 : DO j = 1, ncol_local
738 319251 : alpha = overlap%local_data(i, j)
739 319251 : IF (row_indices(i) .EQ. col_indices(j)) alpha = alpha - 1.0_dp
740 323398 : max_alpha = MAX(max_alpha, ABS(alpha))
741 : END DO
742 : END DO
743 2622 : CALL cp_fm_release(overlap)
744 : END DO
745 866 : CALL mo_array(1)%mo_coeff%matrix_struct%para_env%max(max_alpha)
746 866 : orthonormality = max_alpha
747 : ! write(*,*) "max deviation from orthonormalization ",orthonormality
748 :
749 866 : CALL timestop(handle)
750 :
751 866 : END SUBROUTINE calculate_orthonormality
752 :
753 : ! computes the minimum/maximum magnitudes of C^T C. This could be useful
754 : ! to detect problems in the case of nearly singular overlap matrices.
755 : ! in this case, we expect the ratio of min/max to be large
756 : ! this routine is only similar to mo_orthonormality if S==1
757 : ! **************************************************************************************************
758 : !> \brief ...
759 : !> \param mo_array ...
760 : !> \param mo_mag_min ...
761 : !> \param mo_mag_max ...
762 : ! **************************************************************************************************
763 846 : SUBROUTINE calculate_magnitude(mo_array, mo_mag_min, mo_mag_max)
764 : TYPE(mo_set_type), DIMENSION(:), INTENT(IN) :: mo_array
765 : REAL(KIND=dp) :: mo_mag_min, mo_mag_max
766 :
767 : CHARACTER(len=*), PARAMETER :: routineN = 'calculate_magnitude'
768 :
769 : INTEGER :: handle, ispin, k, n, nspin
770 846 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: evals
771 : TYPE(cp_fm_struct_type), POINTER :: tmp_fm_struct
772 : TYPE(cp_fm_type) :: evecs, overlap
773 :
774 846 : NULLIFY (tmp_fm_struct)
775 :
776 846 : CALL timeset(routineN, handle)
777 :
778 846 : nspin = SIZE(mo_array)
779 846 : mo_mag_min = HUGE(0.0_dp)
780 846 : mo_mag_max = -HUGE(0.0_dp)
781 1692 : DO ispin = 1, nspin
782 : CALL cp_fm_get_info(mo_array(ispin)%mo_coeff, &
783 846 : nrow_global=n, ncol_global=k)
784 2538 : ALLOCATE (evals(k))
785 : CALL cp_fm_struct_create(tmp_fm_struct, nrow_global=k, ncol_global=k, &
786 : para_env=mo_array(ispin)%mo_coeff%matrix_struct%para_env, &
787 846 : context=mo_array(ispin)%mo_coeff%matrix_struct%context)
788 846 : CALL cp_fm_create(overlap, tmp_fm_struct)
789 846 : CALL cp_fm_create(evecs, tmp_fm_struct)
790 846 : CALL cp_fm_struct_release(tmp_fm_struct)
791 : CALL parallel_gemm('T', 'N', k, k, n, 1.0_dp, mo_array(ispin)%mo_coeff, &
792 846 : mo_array(ispin)%mo_coeff, 0.0_dp, overlap)
793 846 : CALL choose_eigv_solver(overlap, evecs, evals)
794 9854 : mo_mag_min = MIN(MINVAL(evals), mo_mag_min)
795 9854 : mo_mag_max = MAX(MAXVAL(evals), mo_mag_max)
796 846 : CALL cp_fm_release(overlap)
797 846 : CALL cp_fm_release(evecs)
798 3384 : DEALLOCATE (evals)
799 : END DO
800 846 : CALL timestop(handle)
801 :
802 1692 : END SUBROUTINE calculate_magnitude
803 :
804 : ! **************************************************************************************************
805 : !> \brief Calculate KS eigenvalues starting from OF MOS
806 : !> \param mos ...
807 : !> \param nspins ...
808 : !> \param ks_rmpv ...
809 : !> \param scf_control ...
810 : !> \param mo_derivs ...
811 : !> \param admm_env ...
812 : !> \par History
813 : !> 02.2013 moved from qs_scf_post_gpw
814 : !>
815 : ! **************************************************************************************************
816 188 : SUBROUTINE make_mo_eig(mos, nspins, ks_rmpv, scf_control, mo_derivs, admm_env)
817 :
818 : TYPE(mo_set_type), DIMENSION(:), INTENT(INOUT) :: mos
819 : INTEGER, INTENT(IN) :: nspins
820 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: ks_rmpv
821 : TYPE(scf_control_type), POINTER :: scf_control
822 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: mo_derivs
823 : TYPE(admm_type), OPTIONAL, POINTER :: admm_env
824 :
825 : CHARACTER(len=*), PARAMETER :: routineN = 'make_mo_eig'
826 :
827 : INTEGER :: handle, homo, ispin, nmo, output_unit
828 188 : REAL(KIND=dp), DIMENSION(:), POINTER :: mo_eigenvalues
829 : TYPE(cp_fm_type), POINTER :: mo_coeff
830 : TYPE(dbcsr_type), POINTER :: mo_coeff_deriv
831 :
832 188 : CALL timeset(routineN, handle)
833 :
834 188 : NULLIFY (mo_coeff_deriv, mo_coeff, mo_eigenvalues)
835 188 : output_unit = cp_logger_get_default_io_unit()
836 :
837 418 : DO ispin = 1, nspins
838 : CALL get_mo_set(mo_set=mos(ispin), mo_coeff=mo_coeff, &
839 230 : eigenvalues=mo_eigenvalues, homo=homo, nmo=nmo)
840 230 : IF (output_unit > 0) WRITE (output_unit, *) " "
841 230 : IF (output_unit > 0) WRITE (output_unit, *) " Eigenvalues of the occupied subspace spin ", ispin
842 : ! IF (homo .NE. nmo) THEN
843 : ! IF (output_unit>0) WRITE(output_unit,*)" and ",nmo-homo," added MO eigenvalues"
844 : ! END IF
845 230 : IF (output_unit > 0) WRITE (output_unit, *) "---------------------------------------------"
846 :
847 230 : IF (scf_control%use_ot) THEN
848 : ! Also rotate the OT derivs, since they are needed for force calculations
849 128 : IF (ASSOCIATED(mo_derivs)) THEN
850 128 : mo_coeff_deriv => mo_derivs(ispin)%matrix
851 : ELSE
852 0 : mo_coeff_deriv => NULL()
853 : END IF
854 :
855 : ! ** If we do ADMM, we add have to modify the kohn-sham matrix
856 128 : IF (PRESENT(admm_env)) THEN
857 0 : CALL admm_correct_for_eigenvalues(ispin, admm_env, ks_rmpv(ispin)%matrix)
858 : END IF
859 :
860 : CALL calculate_subspace_eigenvalues(mo_coeff, ks_rmpv(ispin)%matrix, mo_eigenvalues, &
861 : scr=output_unit, ionode=output_unit > 0, do_rotation=.TRUE., &
862 128 : co_rotate_dbcsr=mo_coeff_deriv)
863 :
864 : ! ** If we do ADMM, we restore the original kohn-sham matrix
865 128 : IF (PRESENT(admm_env)) THEN
866 0 : CALL admm_uncorrect_for_eigenvalues(ispin, admm_env, ks_rmpv(ispin)%matrix)
867 : END IF
868 : ELSE
869 102 : IF (output_unit > 0) WRITE (output_unit, '(4(1X,1F16.8))') mo_eigenvalues(1:homo)
870 : END IF
871 230 : IF (.NOT. scf_control%diagonalization%mom) &
872 230 : CALL set_mo_occupation(mo_set=mos(ispin), smear=scf_control%smear)
873 230 : IF (output_unit > 0) WRITE (output_unit, '(T2,A,F12.6)') &
874 533 : "Fermi Energy [eV] :", mos(ispin)%mu*evolt
875 : END DO
876 :
877 188 : CALL timestop(handle)
878 :
879 188 : END SUBROUTINE make_mo_eig
880 :
881 : END MODULE qs_mo_methods
|