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 Methods used by pao_main.F
10 : !> \author Ole Schuett
11 : ! **************************************************************************************************
12 : MODULE pao_methods
13 : USE ao_util, ONLY: exp_radius
14 : USE atomic_kind_types, ONLY: atomic_kind_type,&
15 : get_atomic_kind
16 : USE basis_set_types, ONLY: gto_basis_set_type
17 : USE bibliography, ONLY: Kolafa2004,&
18 : Kuhne2007,&
19 : cite_reference
20 : USE cp_control_types, ONLY: dft_control_type
21 : USE cp_dbcsr_api, ONLY: &
22 : dbcsr_add, dbcsr_binary_read, dbcsr_complete_redistribute, dbcsr_copy, dbcsr_create, &
23 : dbcsr_desymmetrize, dbcsr_distribution_get, dbcsr_distribution_new, &
24 : dbcsr_distribution_type, dbcsr_filter, dbcsr_get_block_p, dbcsr_get_info, &
25 : dbcsr_iterator_blocks_left, dbcsr_iterator_next_block, dbcsr_iterator_start, &
26 : dbcsr_iterator_stop, dbcsr_iterator_type, dbcsr_p_type, dbcsr_release, dbcsr_scale, &
27 : dbcsr_set, dbcsr_type
28 : USE cp_dbcsr_contrib, ONLY: dbcsr_checksum,&
29 : dbcsr_dot,&
30 : dbcsr_reserve_diag_blocks
31 : USE cp_log_handling, ONLY: cp_get_default_logger,&
32 : cp_logger_type,&
33 : cp_to_string
34 : USE dm_ls_scf_methods, ONLY: density_matrix_trs4,&
35 : ls_scf_init_matrix_S
36 : USE dm_ls_scf_qs, ONLY: ls_scf_dm_to_ks,&
37 : ls_scf_qs_atomic_guess,&
38 : matrix_ls_to_qs,&
39 : matrix_qs_to_ls
40 : USE dm_ls_scf_types, ONLY: ls_mstruct_type,&
41 : ls_scf_env_type
42 : USE iterate_matrix, ONLY: purify_mcweeny
43 : USE kinds, ONLY: default_path_length,&
44 : dp
45 : USE machine, ONLY: m_walltime
46 : USE mathlib, ONLY: binomial,&
47 : diamat_all
48 : USE message_passing, ONLY: mp_para_env_type
49 : USE pao_ml, ONLY: pao_ml_forces
50 : USE pao_model, ONLY: pao_model_forces,&
51 : pao_model_load
52 : USE pao_param, ONLY: pao_calc_AB,&
53 : pao_param_count
54 : USE pao_types, ONLY: pao_env_type
55 : USE particle_types, ONLY: particle_type
56 : USE qs_energy_types, ONLY: qs_energy_type
57 : USE qs_environment_types, ONLY: get_qs_env,&
58 : qs_environment_type
59 : USE qs_initial_guess, ONLY: calculate_atomic_fock_matrix
60 : USE qs_kind_types, ONLY: get_qs_kind,&
61 : pao_descriptor_type,&
62 : pao_potential_type,&
63 : qs_kind_type,&
64 : set_qs_kind
65 : USE qs_ks_methods, ONLY: qs_ks_update_qs_env
66 : USE qs_ks_types, ONLY: qs_ks_did_change
67 : USE qs_rho_methods, ONLY: qs_rho_update_rho
68 : USE qs_rho_types, ONLY: qs_rho_get,&
69 : qs_rho_type
70 :
71 : !$ USE OMP_LIB, ONLY: omp_get_level
72 : #include "./base/base_uses.f90"
73 :
74 : IMPLICIT NONE
75 :
76 : PRIVATE
77 :
78 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'pao_methods'
79 :
80 : PUBLIC :: pao_print_atom_info, pao_init_kinds
81 : PUBLIC :: pao_build_orthogonalizer, pao_build_selector
82 : PUBLIC :: pao_build_diag_distribution
83 : PUBLIC :: pao_build_matrix_X, pao_build_core_hamiltonian
84 : PUBLIC :: pao_test_convergence
85 : PUBLIC :: pao_calc_energy, pao_check_trace_ps
86 : PUBLIC :: pao_store_P, pao_add_forces, pao_guess_initial_P
87 : PUBLIC :: pao_check_grad
88 :
89 : CONTAINS
90 :
91 : ! **************************************************************************************************
92 : !> \brief Initialize qs kinds
93 : !> \param pao ...
94 : !> \param qs_env ...
95 : ! **************************************************************************************************
96 98 : SUBROUTINE pao_init_kinds(pao, qs_env)
97 : TYPE(pao_env_type), POINTER :: pao
98 : TYPE(qs_environment_type), POINTER :: qs_env
99 :
100 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_init_kinds'
101 :
102 : CHARACTER(LEN=default_path_length) :: pao_model_file
103 : INTEGER :: handle, i, ikind, pao_basis_size
104 : TYPE(gto_basis_set_type), POINTER :: basis_set
105 98 : TYPE(pao_descriptor_type), DIMENSION(:), POINTER :: pao_descriptors
106 98 : TYPE(pao_potential_type), DIMENSION(:), POINTER :: pao_potentials
107 98 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
108 :
109 98 : CALL timeset(routineN, handle)
110 98 : CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
111 :
112 236 : DO ikind = 1, SIZE(qs_kind_set)
113 : CALL get_qs_kind(qs_kind_set(ikind), &
114 : basis_set=basis_set, &
115 : pao_basis_size=pao_basis_size, &
116 : pao_model_file=pao_model_file, &
117 : pao_potentials=pao_potentials, &
118 138 : pao_descriptors=pao_descriptors)
119 :
120 138 : IF (pao_basis_size < 1) THEN
121 : ! pao disabled for ikind, set pao_basis_size to size of primary basis
122 12 : CALL set_qs_kind(qs_kind_set(ikind), pao_basis_size=basis_set%nsgf)
123 : END IF
124 :
125 : ! initialize radii of Gaussians to speedup screeing later on
126 200 : DO i = 1, SIZE(pao_potentials)
127 200 : pao_potentials(i)%beta_radius = exp_radius(0, pao_potentials(i)%beta, pao%eps_pgf, 1.0_dp)
128 : END DO
129 156 : DO i = 1, SIZE(pao_descriptors)
130 18 : pao_descriptors(i)%beta_radius = exp_radius(0, pao_descriptors(i)%beta, pao%eps_pgf, 1.0_dp)
131 156 : pao_descriptors(i)%screening_radius = exp_radius(0, pao_descriptors(i)%screening, pao%eps_pgf, 1.0_dp)
132 : END DO
133 :
134 : ! Load torch model.
135 374 : IF (LEN_TRIM(pao_model_file) > 0) THEN
136 8 : IF (.NOT. ALLOCATED(pao%models)) &
137 20 : ALLOCATE (pao%models(SIZE(qs_kind_set)))
138 8 : CALL pao_model_load(pao, qs_env, ikind, pao_model_file, pao%models(ikind))
139 : END IF
140 :
141 : END DO
142 98 : CALL timestop(handle)
143 98 : END SUBROUTINE pao_init_kinds
144 :
145 : ! **************************************************************************************************
146 : !> \brief Prints a one line summary for each atom.
147 : !> \param pao ...
148 : ! **************************************************************************************************
149 98 : SUBROUTINE pao_print_atom_info(pao)
150 : TYPE(pao_env_type), POINTER :: pao
151 :
152 : INTEGER :: iatom, natoms
153 98 : INTEGER, DIMENSION(:), POINTER :: pao_basis, param_cols, param_rows, &
154 98 : pri_basis
155 :
156 98 : CALL dbcsr_get_info(pao%matrix_Y, row_blk_size=pri_basis, col_blk_size=pao_basis)
157 98 : CPASSERT(SIZE(pao_basis) == SIZE(pri_basis))
158 98 : natoms = SIZE(pao_basis)
159 :
160 98 : CALL dbcsr_get_info(pao%matrix_X, row_blk_size=param_rows, col_blk_size=param_cols)
161 98 : CPASSERT(SIZE(param_rows) == natoms .AND. SIZE(param_cols) == natoms)
162 :
163 98 : IF (pao%iw_atoms > 0) THEN
164 12 : DO iatom = 1, natoms
165 : WRITE (pao%iw_atoms, "(A,I7,T20,A,I3,T45,A,I3,T65,A,I3)") &
166 9 : " PAO| atom: ", iatom, &
167 9 : " prim_basis: ", pri_basis(iatom), &
168 9 : " pao_basis: ", pao_basis(iatom), &
169 21 : " pao_params: ", (param_cols(iatom)*param_rows(iatom))
170 : END DO
171 : END IF
172 98 : END SUBROUTINE pao_print_atom_info
173 :
174 : ! **************************************************************************************************
175 : !> \brief Constructs matrix_N and its inverse.
176 : !> \param pao ...
177 : !> \param qs_env ...
178 : ! **************************************************************************************************
179 98 : SUBROUTINE pao_build_orthogonalizer(pao, qs_env)
180 : TYPE(pao_env_type), POINTER :: pao
181 : TYPE(qs_environment_type), POINTER :: qs_env
182 :
183 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_build_orthogonalizer'
184 :
185 : INTEGER :: acol, arow, handle, i, iatom, j, k, N
186 : LOGICAL :: found
187 : REAL(dp) :: v, w
188 98 : REAL(dp), DIMENSION(:), POINTER :: evals
189 98 : REAL(dp), DIMENSION(:, :), POINTER :: A, block_N, block_N_inv, block_S
190 : TYPE(dbcsr_iterator_type) :: iter
191 98 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
192 :
193 98 : CALL timeset(routineN, handle)
194 :
195 98 : CALL get_qs_env(qs_env, matrix_s=matrix_s)
196 :
197 98 : CALL dbcsr_create(pao%matrix_N, template=matrix_s(1)%matrix, name="PAO matrix_N")
198 98 : CALL dbcsr_reserve_diag_blocks(pao%matrix_N)
199 :
200 98 : CALL dbcsr_create(pao%matrix_N_inv, template=matrix_s(1)%matrix, name="PAO matrix_N_inv")
201 98 : CALL dbcsr_reserve_diag_blocks(pao%matrix_N_inv)
202 :
203 : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao,matrix_s) &
204 98 : !$OMP PRIVATE(iter,arow,acol,iatom,block_N,block_N_inv,block_S,found,N,A,evals,k,i,j,w,v)
205 : CALL dbcsr_iterator_start(iter, pao%matrix_N)
206 : DO WHILE (dbcsr_iterator_blocks_left(iter))
207 : CALL dbcsr_iterator_next_block(iter, arow, acol, block_N)
208 : iatom = arow; CPASSERT(arow == acol)
209 :
210 : CALL dbcsr_get_block_p(matrix=pao%matrix_N_inv, row=iatom, col=iatom, block=block_N_inv, found=found)
211 : CPASSERT(ASSOCIATED(block_N_inv))
212 :
213 : CALL dbcsr_get_block_p(matrix=matrix_s(1)%matrix, row=iatom, col=iatom, block=block_S, found=found)
214 : CPASSERT(ASSOCIATED(block_S))
215 :
216 : N = SIZE(block_S, 1); CPASSERT(SIZE(block_S, 1) == SIZE(block_S, 2)) ! primary basis size
217 : ALLOCATE (A(N, N), evals(N))
218 :
219 : ! take square root of atomic overlap matrix
220 : A = block_S
221 : CALL diamat_all(A, evals) !afterwards A contains the eigenvectors
222 : block_N = 0.0_dp
223 : block_N_inv = 0.0_dp
224 : DO k = 1, N
225 : ! NOTE: To maintain a consistent notation with the Berghold paper,
226 : ! the "_inv" is swapped: N^{-1}=sqrt(S); N=sqrt(S)^{-1}
227 : w = 1.0_dp/SQRT(evals(k))
228 : v = SQRT(evals(k))
229 : DO i = 1, N
230 : DO j = 1, N
231 : block_N(i, j) = block_N(i, j) + w*A(i, k)*A(j, k)
232 : block_N_inv(i, j) = block_N_inv(i, j) + v*A(i, k)*A(j, k)
233 : END DO
234 : END DO
235 : END DO
236 : DEALLOCATE (A, evals)
237 : END DO
238 : CALL dbcsr_iterator_stop(iter)
239 : !$OMP END PARALLEL
240 :
241 : ! store a copies of N and N_inv that are distributed according to pao%diag_distribution
242 : CALL dbcsr_create(pao%matrix_N_diag, &
243 : name="PAO matrix_N_diag", &
244 : dist=pao%diag_distribution, &
245 98 : template=matrix_s(1)%matrix)
246 98 : CALL dbcsr_reserve_diag_blocks(pao%matrix_N_diag)
247 98 : CALL dbcsr_complete_redistribute(pao%matrix_N, pao%matrix_N_diag)
248 : CALL dbcsr_create(pao%matrix_N_inv_diag, &
249 : name="PAO matrix_N_inv_diag", &
250 : dist=pao%diag_distribution, &
251 98 : template=matrix_s(1)%matrix)
252 98 : CALL dbcsr_reserve_diag_blocks(pao%matrix_N_inv_diag)
253 98 : CALL dbcsr_complete_redistribute(pao%matrix_N_inv, pao%matrix_N_inv_diag)
254 :
255 98 : CALL timestop(handle)
256 98 : END SUBROUTINE pao_build_orthogonalizer
257 :
258 : ! **************************************************************************************************
259 : !> \brief Build rectangular matrix to converert between primary and PAO basis.
260 : !> \param pao ...
261 : !> \param qs_env ...
262 : ! **************************************************************************************************
263 98 : SUBROUTINE pao_build_selector(pao, qs_env)
264 : TYPE(pao_env_type), POINTER :: pao
265 : TYPE(qs_environment_type), POINTER :: qs_env
266 :
267 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_build_selector'
268 :
269 : INTEGER :: acol, arow, handle, i, iatom, ikind, M, &
270 : natoms
271 98 : INTEGER, DIMENSION(:), POINTER :: blk_sizes_aux, blk_sizes_pri
272 98 : REAL(dp), DIMENSION(:, :), POINTER :: block_Y
273 : TYPE(dbcsr_iterator_type) :: iter
274 98 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
275 98 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
276 98 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
277 :
278 98 : CALL timeset(routineN, handle)
279 :
280 : CALL get_qs_env(qs_env, &
281 : natom=natoms, &
282 : matrix_s=matrix_s, &
283 : qs_kind_set=qs_kind_set, &
284 98 : particle_set=particle_set)
285 :
286 98 : CALL dbcsr_get_info(matrix_s(1)%matrix, col_blk_size=blk_sizes_pri)
287 :
288 294 : ALLOCATE (blk_sizes_aux(natoms))
289 336 : DO iatom = 1, natoms
290 238 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
291 238 : CALL get_qs_kind(qs_kind_set(ikind), pao_basis_size=M)
292 238 : CPASSERT(M > 0)
293 238 : IF (blk_sizes_pri(iatom) < M) &
294 0 : CPABORT("PAO basis size exceeds primary basis size.")
295 574 : blk_sizes_aux(iatom) = M
296 : END DO
297 :
298 : CALL dbcsr_create(pao%matrix_Y, &
299 : template=matrix_s(1)%matrix, &
300 : matrix_type="N", &
301 : row_blk_size=blk_sizes_pri, &
302 : col_blk_size=blk_sizes_aux, &
303 98 : name="PAO matrix_Y")
304 98 : DEALLOCATE (blk_sizes_aux)
305 :
306 98 : CALL dbcsr_reserve_diag_blocks(pao%matrix_Y)
307 :
308 : !$OMP PARALLEL DEFAULT(NONE) SHARED(pao) &
309 98 : !$OMP PRIVATE(iter,arow,acol,block_Y,i,M)
310 : CALL dbcsr_iterator_start(iter, pao%matrix_Y)
311 : DO WHILE (dbcsr_iterator_blocks_left(iter))
312 : CALL dbcsr_iterator_next_block(iter, arow, acol, block_Y)
313 : M = SIZE(block_Y, 2) ! size of pao basis
314 : block_Y = 0.0_dp
315 : DO i = 1, M
316 : block_Y(i, i) = 1.0_dp
317 : END DO
318 : END DO
319 : CALL dbcsr_iterator_stop(iter)
320 : !$OMP END PARALLEL
321 :
322 98 : CALL timestop(handle)
323 98 : END SUBROUTINE pao_build_selector
324 :
325 : ! **************************************************************************************************
326 : !> \brief Creates new DBCSR distribution which spreads diagonal blocks evenly across ranks
327 : !> \param pao ...
328 : !> \param qs_env ...
329 : ! **************************************************************************************************
330 98 : SUBROUTINE pao_build_diag_distribution(pao, qs_env)
331 : TYPE(pao_env_type), POINTER :: pao
332 : TYPE(qs_environment_type), POINTER :: qs_env
333 :
334 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_build_diag_distribution'
335 :
336 : INTEGER :: handle, iatom, natoms, pgrid_cols, &
337 : pgrid_rows
338 98 : INTEGER, DIMENSION(:), POINTER :: diag_col_dist, diag_row_dist
339 : TYPE(dbcsr_distribution_type) :: main_dist
340 98 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
341 :
342 98 : CALL timeset(routineN, handle)
343 :
344 98 : CALL get_qs_env(qs_env, natom=natoms, matrix_s=matrix_s)
345 :
346 : ! get processor grid from matrix_s
347 98 : CALL dbcsr_get_info(matrix=matrix_s(1)%matrix, distribution=main_dist)
348 98 : CALL dbcsr_distribution_get(main_dist, nprows=pgrid_rows, npcols=pgrid_cols)
349 :
350 : ! create new mapping of matrix-grid to processor-grid
351 490 : ALLOCATE (diag_row_dist(natoms), diag_col_dist(natoms))
352 336 : DO iatom = 1, natoms
353 238 : diag_row_dist(iatom) = MOD(iatom - 1, pgrid_rows)
354 336 : diag_col_dist(iatom) = MOD((iatom - 1)/pgrid_rows, pgrid_cols)
355 : END DO
356 :
357 : ! instanciate distribution object
358 : CALL dbcsr_distribution_new(pao%diag_distribution, template=main_dist, &
359 98 : row_dist=diag_row_dist, col_dist=diag_col_dist)
360 :
361 98 : DEALLOCATE (diag_row_dist, diag_col_dist)
362 :
363 98 : CALL timestop(handle)
364 196 : END SUBROUTINE pao_build_diag_distribution
365 :
366 : ! **************************************************************************************************
367 : !> \brief Creates the matrix_X
368 : !> \param pao ...
369 : !> \param qs_env ...
370 : ! **************************************************************************************************
371 98 : SUBROUTINE pao_build_matrix_X(pao, qs_env)
372 : TYPE(pao_env_type), POINTER :: pao
373 : TYPE(qs_environment_type), POINTER :: qs_env
374 :
375 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_build_matrix_X'
376 :
377 : INTEGER :: handle, iatom, ikind, natoms
378 98 : INTEGER, DIMENSION(:), POINTER :: col_blk_size, row_blk_size
379 98 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
380 :
381 98 : CALL timeset(routineN, handle)
382 :
383 : CALL get_qs_env(qs_env, &
384 : natom=natoms, &
385 98 : particle_set=particle_set)
386 :
387 : ! determine block-sizes of matrix_X
388 490 : ALLOCATE (row_blk_size(natoms), col_blk_size(natoms))
389 336 : col_blk_size = 1
390 336 : DO iatom = 1, natoms
391 238 : CALL get_atomic_kind(particle_set(iatom)%atomic_kind, kind_number=ikind)
392 336 : CALL pao_param_count(pao, qs_env, ikind, nparams=row_blk_size(iatom))
393 : END DO
394 :
395 : ! build actual matrix_X
396 : CALL dbcsr_create(pao%matrix_X, &
397 : name="PAO matrix_X", &
398 : dist=pao%diag_distribution, &
399 : matrix_type="N", &
400 : row_blk_size=row_blk_size, &
401 98 : col_blk_size=col_blk_size)
402 98 : DEALLOCATE (row_blk_size, col_blk_size)
403 :
404 98 : CALL dbcsr_reserve_diag_blocks(pao%matrix_X)
405 98 : CALL dbcsr_set(pao%matrix_X, 0.0_dp)
406 :
407 98 : CALL timestop(handle)
408 98 : END SUBROUTINE pao_build_matrix_X
409 :
410 : ! **************************************************************************************************
411 : !> \brief Creates the matrix_H0 which contains the core hamiltonian
412 : !> \param pao ...
413 : !> \param qs_env ...
414 : ! **************************************************************************************************
415 98 : SUBROUTINE pao_build_core_hamiltonian(pao, qs_env)
416 : TYPE(pao_env_type), POINTER :: pao
417 : TYPE(qs_environment_type), POINTER :: qs_env
418 :
419 98 : TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
420 98 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
421 98 : TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
422 :
423 : CALL get_qs_env(qs_env, &
424 : matrix_s=matrix_s, &
425 : atomic_kind_set=atomic_kind_set, &
426 98 : qs_kind_set=qs_kind_set)
427 :
428 : ! allocate matrix_H0
429 : CALL dbcsr_create(pao%matrix_H0, &
430 : name="PAO matrix_H0", &
431 : dist=pao%diag_distribution, &
432 98 : template=matrix_s(1)%matrix)
433 98 : CALL dbcsr_reserve_diag_blocks(pao%matrix_H0)
434 :
435 : ! calculate initial atomic fock matrix H0
436 : ! Can't use matrix_ks from ls_scf_qs_atomic_guess(), because it's not rotationally invariant.
437 : ! getting H0 directly from the atomic code
438 : CALL calculate_atomic_fock_matrix(pao%matrix_H0, &
439 : atomic_kind_set, &
440 : qs_kind_set, &
441 98 : ounit=pao%iw)
442 :
443 98 : END SUBROUTINE pao_build_core_hamiltonian
444 :
445 : ! **************************************************************************************************
446 : !> \brief Test whether the PAO optimization has reached convergence
447 : !> \param pao ...
448 : !> \param ls_scf_env ...
449 : !> \param new_energy ...
450 : !> \param is_converged ...
451 : ! **************************************************************************************************
452 2616 : SUBROUTINE pao_test_convergence(pao, ls_scf_env, new_energy, is_converged)
453 : TYPE(pao_env_type), POINTER :: pao
454 : TYPE(ls_scf_env_type) :: ls_scf_env
455 : REAL(KIND=dp), INTENT(IN) :: new_energy
456 : LOGICAL, INTENT(OUT) :: is_converged
457 :
458 : REAL(KIND=dp) :: energy_diff, loop_eps, now, time_diff
459 :
460 : ! calculate progress
461 2616 : energy_diff = new_energy - pao%energy_prev
462 2616 : pao%energy_prev = new_energy
463 2616 : now = m_walltime()
464 2616 : time_diff = now - pao%step_start_time
465 2616 : pao%step_start_time = now
466 :
467 : ! convergence criterion
468 2616 : loop_eps = pao%norm_G/ls_scf_env%nelectron_total
469 2616 : is_converged = loop_eps < pao%eps_pao
470 :
471 2616 : IF (pao%istep > 1) THEN
472 2540 : IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| energy improvement:", energy_diff
473 : ! CPWARN_IF(energy_diff>0.0_dp, "PAO| energy increased")
474 :
475 : ! print one-liner
476 2540 : IF (pao%iw > 0) WRITE (pao%iw, '(A,I6,11X,F20.9,1X,E10.3,1X,E10.3,1X,F9.3)') &
477 1270 : " PAO| step ", &
478 1270 : pao%istep, &
479 1270 : new_energy, &
480 1270 : loop_eps, &
481 1270 : pao%linesearch%step_size, & !prev step, which let to the current energy
482 2540 : time_diff
483 : END IF
484 2616 : END SUBROUTINE pao_test_convergence
485 :
486 : ! **************************************************************************************************
487 : !> \brief Calculate the pao energy
488 : !> \param pao ...
489 : !> \param qs_env ...
490 : !> \param ls_scf_env ...
491 : !> \param energy ...
492 : ! **************************************************************************************************
493 11806 : SUBROUTINE pao_calc_energy(pao, qs_env, ls_scf_env, energy)
494 : TYPE(pao_env_type), POINTER :: pao
495 : TYPE(qs_environment_type), POINTER :: qs_env
496 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
497 : REAL(KIND=dp), INTENT(OUT) :: energy
498 :
499 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_calc_energy'
500 :
501 : INTEGER :: handle, ispin
502 : REAL(KIND=dp) :: penalty, trace_PH
503 :
504 11806 : CALL timeset(routineN, handle)
505 :
506 : ! calculate matrix U, which determines the pao basis
507 11806 : CALL pao_calc_AB(pao, qs_env, ls_scf_env, gradient=.FALSE., penalty=penalty)
508 :
509 : ! calculat S, S_inv, S_sqrt, and S_sqrt_inv in the new pao basis
510 11806 : CALL pao_rebuild_S(qs_env, ls_scf_env)
511 :
512 : ! calculate the density matrix P in the pao basis
513 11806 : CALL pao_dm_trs4(qs_env, ls_scf_env)
514 :
515 : ! calculate the energy from the trace(PH) in the pao basis
516 11806 : energy = 0.0_dp
517 23612 : DO ispin = 1, ls_scf_env%nspins
518 11806 : CALL dbcsr_dot(ls_scf_env%matrix_p(ispin), ls_scf_env%matrix_ks(ispin), trace_PH)
519 23612 : energy = energy + trace_PH
520 : END DO
521 :
522 : ! add penalty term
523 11806 : energy = energy + penalty
524 :
525 11806 : IF (pao%iw > 0) THEN
526 5903 : WRITE (pao%iw, *) ""
527 5903 : WRITE (pao%iw, *) "PAO| energy:", energy, "penalty:", penalty
528 : END IF
529 11806 : CALL timestop(handle)
530 11806 : END SUBROUTINE pao_calc_energy
531 :
532 : ! **************************************************************************************************
533 : !> \brief Ensure that the number of electrons is correct.
534 : !> \param ls_scf_env ...
535 : ! **************************************************************************************************
536 10326 : SUBROUTINE pao_check_trace_PS(ls_scf_env)
537 : TYPE(ls_scf_env_type) :: ls_scf_env
538 :
539 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_check_trace_PS'
540 :
541 : INTEGER :: handle, ispin
542 : REAL(KIND=dp) :: tmp, trace_PS
543 : TYPE(dbcsr_type) :: matrix_S_desym
544 :
545 10326 : CALL timeset(routineN, handle)
546 10326 : CALL dbcsr_create(matrix_S_desym, template=ls_scf_env%matrix_s, matrix_type="N")
547 10326 : CALL dbcsr_desymmetrize(ls_scf_env%matrix_s, matrix_S_desym)
548 :
549 10326 : trace_PS = 0.0_dp
550 20652 : DO ispin = 1, ls_scf_env%nspins
551 10326 : CALL dbcsr_dot(ls_scf_env%matrix_p(ispin), matrix_S_desym, tmp)
552 20652 : trace_PS = trace_PS + tmp
553 : END DO
554 :
555 10326 : CALL dbcsr_release(matrix_S_desym)
556 :
557 10326 : IF (ABS(ls_scf_env%nelectron_total - trace_PS) > 0.5) &
558 0 : CPABORT("Number of electrons wrong. Trace(PS) ="//cp_to_string(trace_PS))
559 :
560 10326 : CALL timestop(handle)
561 10326 : END SUBROUTINE pao_check_trace_PS
562 :
563 : ! **************************************************************************************************
564 : !> \brief Read primary density matrix from file.
565 : !> \param pao ...
566 : !> \param qs_env ...
567 : ! **************************************************************************************************
568 56 : SUBROUTINE pao_read_preopt_dm(pao, qs_env)
569 : TYPE(pao_env_type), POINTER :: pao
570 : TYPE(qs_environment_type), POINTER :: qs_env
571 :
572 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_read_preopt_dm'
573 :
574 : INTEGER :: handle, ispin
575 : REAL(KIND=dp) :: cs_pos
576 : TYPE(dbcsr_distribution_type) :: dist
577 28 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s, rho_ao
578 : TYPE(dbcsr_type) :: matrix_tmp
579 : TYPE(dft_control_type), POINTER :: dft_control
580 : TYPE(qs_energy_type), POINTER :: energy
581 : TYPE(qs_rho_type), POINTER :: rho
582 :
583 28 : CALL timeset(routineN, handle)
584 :
585 : CALL get_qs_env(qs_env, &
586 : dft_control=dft_control, &
587 : matrix_s=matrix_s, &
588 : rho=rho, &
589 28 : energy=energy)
590 :
591 28 : CALL qs_rho_get(rho, rho_ao=rho_ao)
592 :
593 28 : IF (dft_control%nspins /= 1) CPABORT("open shell not yet implemented")
594 :
595 28 : CALL dbcsr_get_info(matrix_s(1)%matrix, distribution=dist)
596 :
597 56 : DO ispin = 1, dft_control%nspins
598 28 : CALL dbcsr_binary_read(pao%preopt_dm_file, matrix_new=matrix_tmp, distribution=dist)
599 28 : cs_pos = dbcsr_checksum(matrix_tmp, pos=.TRUE.)
600 28 : IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| Read restart DM "// &
601 14 : TRIM(pao%preopt_dm_file)//" with checksum: ", cs_pos
602 28 : CALL dbcsr_copy(rho_ao(ispin)%matrix, matrix_tmp, keep_sparsity=.TRUE.)
603 56 : CALL dbcsr_release(matrix_tmp)
604 : END DO
605 :
606 : ! calculate corresponding ks matrix
607 28 : CALL qs_rho_update_rho(rho, qs_env=qs_env)
608 28 : CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
609 : CALL qs_ks_update_qs_env(qs_env, calculate_forces=.FALSE., &
610 28 : just_energy=.FALSE., print_active=.TRUE.)
611 28 : IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| Quickstep energy from restart density:", energy%total
612 :
613 28 : CALL timestop(handle)
614 :
615 28 : END SUBROUTINE pao_read_preopt_dm
616 :
617 : ! **************************************************************************************************
618 : !> \brief Rebuilds S, S_inv, S_sqrt, and S_sqrt_inv in the pao basis
619 : !> \param qs_env ...
620 : !> \param ls_scf_env ...
621 : ! **************************************************************************************************
622 11806 : SUBROUTINE pao_rebuild_S(qs_env, ls_scf_env)
623 : TYPE(qs_environment_type), POINTER :: qs_env
624 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
625 :
626 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_rebuild_S'
627 :
628 : INTEGER :: handle
629 11806 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
630 :
631 11806 : CALL timeset(routineN, handle)
632 :
633 11806 : CALL dbcsr_release(ls_scf_env%matrix_s_inv)
634 11806 : CALL dbcsr_release(ls_scf_env%matrix_s_sqrt)
635 11806 : CALL dbcsr_release(ls_scf_env%matrix_s_sqrt_inv)
636 :
637 11806 : CALL get_qs_env(qs_env, matrix_s=matrix_s)
638 11806 : CALL ls_scf_init_matrix_s(matrix_s(1)%matrix, ls_scf_env)
639 :
640 11806 : CALL timestop(handle)
641 11806 : END SUBROUTINE pao_rebuild_S
642 :
643 : ! **************************************************************************************************
644 : !> \brief Calculate density matrix using TRS4 purification
645 : !> \param qs_env ...
646 : !> \param ls_scf_env ...
647 : ! **************************************************************************************************
648 11806 : SUBROUTINE pao_dm_trs4(qs_env, ls_scf_env)
649 : TYPE(qs_environment_type), POINTER :: qs_env
650 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
651 :
652 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_dm_trs4'
653 :
654 : CHARACTER(LEN=default_path_length) :: project_name
655 : INTEGER :: handle, ispin, nelectron_spin_real, nspin
656 : LOGICAL :: converged
657 : REAL(KIND=dp) :: homo_spin, lumo_spin, mu_spin
658 : TYPE(cp_logger_type), POINTER :: logger
659 11806 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_ks
660 :
661 11806 : CALL timeset(routineN, handle)
662 11806 : logger => cp_get_default_logger()
663 11806 : project_name = logger%iter_info%project_name
664 11806 : nspin = ls_scf_env%nspins
665 :
666 11806 : CALL get_qs_env(qs_env, matrix_ks=matrix_ks)
667 23612 : DO ispin = 1, nspin
668 : CALL matrix_qs_to_ls(ls_scf_env%matrix_ks(ispin), matrix_ks(ispin)%matrix, &
669 11806 : ls_scf_env%ls_mstruct, covariant=.TRUE.)
670 :
671 11806 : nelectron_spin_real = ls_scf_env%nelectron_spin(ispin)
672 11806 : IF (ls_scf_env%nspins == 1) nelectron_spin_real = nelectron_spin_real/2
673 : CALL density_matrix_trs4(ls_scf_env%matrix_p(ispin), ls_scf_env%matrix_ks(ispin), &
674 : ls_scf_env%matrix_s_sqrt_inv, &
675 : nelectron_spin_real, ls_scf_env%eps_filter, homo_spin, lumo_spin, mu_spin, &
676 : dynamic_threshold=.FALSE., converged=converged, &
677 : max_iter_lanczos=ls_scf_env%max_iter_lanczos, &
678 11806 : eps_lanczos=ls_scf_env%eps_lanczos)
679 23612 : IF (.NOT. converged) CPABORT("TRS4 did not converge")
680 : END DO
681 :
682 11806 : IF (nspin == 1) CALL dbcsr_scale(ls_scf_env%matrix_p(1), 2.0_dp)
683 :
684 11806 : CALL timestop(handle)
685 11806 : END SUBROUTINE pao_dm_trs4
686 :
687 : ! **************************************************************************************************
688 : !> \brief Debugging routine for checking the analytic gradient.
689 : !> \param pao ...
690 : !> \param qs_env ...
691 : !> \param ls_scf_env ...
692 : ! **************************************************************************************************
693 2628 : SUBROUTINE pao_check_grad(pao, qs_env, ls_scf_env)
694 : TYPE(pao_env_type), POINTER :: pao
695 : TYPE(qs_environment_type), POINTER :: qs_env
696 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
697 :
698 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_check_grad'
699 :
700 : INTEGER :: handle, i, iatom, j, natoms
701 2616 : INTEGER, DIMENSION(:), POINTER :: blk_sizes_col, blk_sizes_row
702 : LOGICAL :: found
703 : REAL(dp) :: delta, delta_max, eps, Gij_num
704 2616 : REAL(dp), DIMENSION(:, :), POINTER :: block_G, block_X
705 : TYPE(ls_mstruct_type), POINTER :: ls_mstruct
706 : TYPE(mp_para_env_type), POINTER :: para_env
707 :
708 2604 : IF (pao%check_grad_tol < 0.0_dp) RETURN ! no checking
709 :
710 12 : CALL timeset(routineN, handle)
711 :
712 12 : ls_mstruct => ls_scf_env%ls_mstruct
713 :
714 12 : CALL get_qs_env(qs_env, para_env=para_env, natom=natoms)
715 :
716 12 : eps = pao%num_grad_eps
717 12 : delta_max = 0.0_dp
718 :
719 12 : CALL dbcsr_get_info(pao%matrix_X, col_blk_size=blk_sizes_col, row_blk_size=blk_sizes_row)
720 :
721 : ! can not use an iterator here, because other DBCSR routines are called within loop.
722 38 : DO iatom = 1, natoms
723 26 : IF (pao%iw > 0) WRITE (pao%iw, *) 'PAO| checking gradient of atom ', iatom
724 26 : CALL dbcsr_get_block_p(matrix=pao%matrix_X, row=iatom, col=iatom, block=block_X, found=found)
725 :
726 26 : IF (ASSOCIATED(block_X)) THEN !only one node actually has the block
727 13 : CALL dbcsr_get_block_p(matrix=pao%matrix_G, row=iatom, col=iatom, block=block_G, found=found)
728 13 : CPASSERT(ASSOCIATED(block_G))
729 : END IF
730 :
731 586 : DO i = 1, blk_sizes_row(iatom)
732 1070 : DO j = 1, blk_sizes_col(iatom)
733 828 : SELECT CASE (pao%num_grad_order)
734 : CASE (2) ! calculate derivative to 2th order
735 306 : Gij_num = -eval_point(block_X, i, j, -eps, pao, ls_scf_env, qs_env)
736 306 : Gij_num = Gij_num + eval_point(block_X, i, j, +eps, pao, ls_scf_env, qs_env)
737 306 : Gij_num = Gij_num/(2.0_dp*eps)
738 :
739 : CASE (4) ! calculate derivative to 4th order
740 180 : Gij_num = eval_point(block_X, i, j, -2_dp*eps, pao, ls_scf_env, qs_env)
741 180 : Gij_num = Gij_num - 8_dp*eval_point(block_X, i, j, -1_dp*eps, pao, ls_scf_env, qs_env)
742 180 : Gij_num = Gij_num + 8_dp*eval_point(block_X, i, j, +1_dp*eps, pao, ls_scf_env, qs_env)
743 180 : Gij_num = Gij_num - eval_point(block_X, i, j, +2_dp*eps, pao, ls_scf_env, qs_env)
744 180 : Gij_num = Gij_num/(12.0_dp*eps)
745 :
746 : CASE (6) ! calculate derivative to 6th order
747 36 : Gij_num = -1_dp*eval_point(block_X, i, j, -3_dp*eps, pao, ls_scf_env, qs_env)
748 36 : Gij_num = Gij_num + 9_dp*eval_point(block_X, i, j, -2_dp*eps, pao, ls_scf_env, qs_env)
749 36 : Gij_num = Gij_num - 45_dp*eval_point(block_X, i, j, -1_dp*eps, pao, ls_scf_env, qs_env)
750 36 : Gij_num = Gij_num + 45_dp*eval_point(block_X, i, j, +1_dp*eps, pao, ls_scf_env, qs_env)
751 36 : Gij_num = Gij_num - 9_dp*eval_point(block_X, i, j, +2_dp*eps, pao, ls_scf_env, qs_env)
752 36 : Gij_num = Gij_num + 1_dp*eval_point(block_X, i, j, +3_dp*eps, pao, ls_scf_env, qs_env)
753 36 : Gij_num = Gij_num/(60.0_dp*eps)
754 :
755 : CASE DEFAULT
756 522 : CPABORT("Unsupported numerical derivative order: "//cp_to_string(pao%num_grad_order))
757 : END SELECT
758 :
759 1044 : IF (ASSOCIATED(block_X)) THEN
760 261 : delta = ABS(Gij_num - block_G(i, j))
761 261 : delta_max = MAX(delta_max, delta)
762 : !WRITE (*,*) "gradient check", iatom, i, j, Gij_num, block_G(i,j), delta
763 : END IF
764 : END DO
765 : END DO
766 : END DO
767 :
768 12 : CALL para_env%max(delta_max)
769 12 : IF (pao%iw > 0) WRITE (pao%iw, *) 'PAO| checked gradient, max delta:', delta_max
770 12 : IF (delta_max > pao%check_grad_tol) CALL cp_abort(__LOCATION__, &
771 0 : "Analytic and numeric gradients differ too much:"//cp_to_string(delta_max))
772 :
773 12 : CALL timestop(handle)
774 2616 : END SUBROUTINE pao_check_grad
775 :
776 : ! **************************************************************************************************
777 : !> \brief Helper routine for pao_check_grad()
778 : !> \param block_X ...
779 : !> \param i ...
780 : !> \param j ...
781 : !> \param eps ...
782 : !> \param pao ...
783 : !> \param ls_scf_env ...
784 : !> \param qs_env ...
785 : !> \return ...
786 : ! **************************************************************************************************
787 3096 : FUNCTION eval_point(block_X, i, j, eps, pao, ls_scf_env, qs_env) RESULT(energy)
788 : REAL(dp), DIMENSION(:, :), POINTER :: block_X
789 : INTEGER, INTENT(IN) :: i, j
790 : REAL(dp), INTENT(IN) :: eps
791 : TYPE(pao_env_type), POINTER :: pao
792 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
793 : TYPE(qs_environment_type), POINTER :: qs_env
794 : REAL(dp) :: energy
795 :
796 : REAL(dp) :: old_Xij
797 :
798 1548 : IF (ASSOCIATED(block_X)) THEN
799 774 : old_Xij = block_X(i, j) ! backup old block_X
800 774 : block_X(i, j) = block_X(i, j) + eps ! add perturbation
801 : END IF
802 :
803 : ! calculate energy
804 1548 : CALL pao_calc_energy(pao, qs_env, ls_scf_env, energy)
805 :
806 : ! restore old block_X
807 1548 : IF (ASSOCIATED(block_X)) THEN
808 774 : block_X(i, j) = old_Xij
809 : END IF
810 :
811 1548 : END FUNCTION eval_point
812 :
813 : ! **************************************************************************************************
814 : !> \brief Stores density matrix as initial guess for next SCF optimization.
815 : !> \param qs_env ...
816 : !> \param ls_scf_env ...
817 : ! **************************************************************************************************
818 588 : SUBROUTINE pao_store_P(qs_env, ls_scf_env)
819 : TYPE(qs_environment_type), POINTER :: qs_env
820 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
821 :
822 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_store_P'
823 :
824 : INTEGER :: handle, ispin, istore
825 294 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
826 : TYPE(dft_control_type), POINTER :: dft_control
827 : TYPE(ls_mstruct_type), POINTER :: ls_mstruct
828 : TYPE(pao_env_type), POINTER :: pao
829 :
830 0 : IF (ls_scf_env%scf_history%nstore == 0) RETURN
831 294 : CALL timeset(routineN, handle)
832 294 : ls_mstruct => ls_scf_env%ls_mstruct
833 294 : pao => ls_scf_env%pao_env
834 294 : CALL get_qs_env(qs_env, dft_control=dft_control, matrix_s=matrix_s)
835 :
836 294 : ls_scf_env%scf_history%istore = ls_scf_env%scf_history%istore + 1
837 294 : istore = MOD(ls_scf_env%scf_history%istore - 1, ls_scf_env%scf_history%nstore) + 1
838 294 : IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| Storing density matrix for ASPC guess in slot:", istore
839 :
840 : ! initialize storage
841 294 : IF (ls_scf_env%scf_history%istore <= ls_scf_env%scf_history%nstore) THEN
842 216 : DO ispin = 1, dft_control%nspins
843 216 : CALL dbcsr_create(ls_scf_env%scf_history%matrix(ispin, istore), template=matrix_s(1)%matrix)
844 : END DO
845 : END IF
846 :
847 : ! We are storing the density matrix in the non-orthonormal primary basis.
848 : ! While the orthonormal basis would yield better extrapolations,
849 : ! we simply can not afford to calculat S_sqrt in the primary basis.
850 588 : DO ispin = 1, dft_control%nspins
851 : ! transform into primary basis
852 : CALL matrix_ls_to_qs(ls_scf_env%scf_history%matrix(ispin, istore), ls_scf_env%matrix_p(ispin), &
853 588 : ls_scf_env%ls_mstruct, covariant=.FALSE., keep_sparsity=.FALSE.)
854 : END DO
855 :
856 294 : CALL timestop(handle)
857 294 : END SUBROUTINE pao_store_P
858 :
859 : ! **************************************************************************************************
860 : !> \brief Provide an initial guess for the density matrix
861 : !> \param pao ...
862 : !> \param qs_env ...
863 : !> \param ls_scf_env ...
864 : ! **************************************************************************************************
865 294 : SUBROUTINE pao_guess_initial_P(pao, qs_env, ls_scf_env)
866 : TYPE(pao_env_type), POINTER :: pao
867 : TYPE(qs_environment_type), POINTER :: qs_env
868 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
869 :
870 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_guess_initial_P'
871 :
872 : INTEGER :: handle
873 :
874 294 : CALL timeset(routineN, handle)
875 :
876 294 : IF (ls_scf_env%scf_history%istore > 0) THEN
877 196 : CALL pao_aspc_guess_P(pao, qs_env, ls_scf_env)
878 196 : pao%need_initial_scf = .TRUE.
879 : ELSE
880 98 : IF (LEN_TRIM(pao%preopt_dm_file) > 0) THEN
881 28 : CALL pao_read_preopt_dm(pao, qs_env)
882 28 : pao%need_initial_scf = .FALSE.
883 28 : pao%preopt_dm_file = "" ! load only for first MD step
884 : ELSE
885 70 : CALL ls_scf_qs_atomic_guess(qs_env, ls_scf_env, ls_scf_env%energy_init)
886 70 : IF (pao%iw > 0) WRITE (pao%iw, '(A,F20.9)') &
887 35 : " PAO| Energy from initial atomic guess:", ls_scf_env%energy_init
888 70 : pao%need_initial_scf = .TRUE.
889 : END IF
890 : END IF
891 :
892 294 : CALL timestop(handle)
893 :
894 294 : END SUBROUTINE pao_guess_initial_P
895 :
896 : ! **************************************************************************************************
897 : !> \brief Run the Always Stable Predictor-Corrector to guess an initial density matrix
898 : !> \param pao ...
899 : !> \param qs_env ...
900 : !> \param ls_scf_env ...
901 : ! **************************************************************************************************
902 196 : SUBROUTINE pao_aspc_guess_P(pao, qs_env, ls_scf_env)
903 : TYPE(pao_env_type), POINTER :: pao
904 : TYPE(qs_environment_type), POINTER :: qs_env
905 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
906 :
907 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_aspc_guess_P'
908 :
909 : INTEGER :: handle, iaspc, ispin, istore, naspc
910 : REAL(dp) :: alpha
911 196 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
912 : TYPE(dbcsr_type) :: matrix_P
913 : TYPE(dft_control_type), POINTER :: dft_control
914 : TYPE(ls_mstruct_type), POINTER :: ls_mstruct
915 :
916 196 : CALL timeset(routineN, handle)
917 196 : ls_mstruct => ls_scf_env%ls_mstruct
918 196 : CPASSERT(ls_scf_env%scf_history%istore > 0)
919 196 : CALL cite_reference(Kolafa2004)
920 196 : CALL cite_reference(Kuhne2007)
921 196 : CALL get_qs_env(qs_env, dft_control=dft_control, matrix_s=matrix_s)
922 :
923 196 : IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| Calculating initial guess with ASPC"
924 :
925 196 : CALL dbcsr_create(matrix_P, template=matrix_s(1)%matrix)
926 :
927 196 : naspc = MIN(ls_scf_env%scf_history%istore, ls_scf_env%scf_history%nstore)
928 392 : DO ispin = 1, dft_control%nspins
929 : ! actual extrapolation
930 196 : CALL dbcsr_set(matrix_P, 0.0_dp)
931 416 : DO iaspc = 1, naspc
932 : alpha = (-1.0_dp)**(iaspc + 1)*REAL(iaspc, KIND=dp)* &
933 220 : binomial(2*naspc, naspc - iaspc)/binomial(2*naspc - 2, naspc - 1)
934 220 : istore = MOD(ls_scf_env%scf_history%istore - iaspc, ls_scf_env%scf_history%nstore) + 1
935 416 : CALL dbcsr_add(matrix_P, ls_scf_env%scf_history%matrix(ispin, istore), 1.0_dp, alpha)
936 : END DO
937 :
938 : ! transform back from primary basis into pao basis
939 392 : CALL matrix_qs_to_ls(ls_scf_env%matrix_p(ispin), matrix_P, ls_scf_env%ls_mstruct, covariant=.FALSE.)
940 : END DO
941 :
942 196 : CALL dbcsr_release(matrix_P)
943 :
944 : ! linear combination of P's is not idempotent. A bit of McWeeny is needed to ensure it is again
945 392 : DO ispin = 1, dft_control%nspins
946 196 : IF (dft_control%nspins == 1) CALL dbcsr_scale(ls_scf_env%matrix_p(ispin), 0.5_dp)
947 : ! to ensure that noisy blocks do not build up during MD (in particular with curvy) filter that guess a bit more
948 196 : CALL dbcsr_filter(ls_scf_env%matrix_p(ispin), ls_scf_env%eps_filter**(2.0_dp/3.0_dp))
949 : ! we could go to the orthonomal basis, but it seems not worth the trouble
950 : ! TODO : 10 iterations is a conservative upper bound, figure out when it fails
951 196 : CALL purify_mcweeny(ls_scf_env%matrix_p(ispin:ispin), ls_scf_env%matrix_s, ls_scf_env%eps_filter, 10)
952 392 : IF (dft_control%nspins == 1) CALL dbcsr_scale(ls_scf_env%matrix_p(ispin), 2.0_dp)
953 : END DO
954 :
955 196 : CALL pao_check_trace_PS(ls_scf_env) ! sanity check
956 :
957 : ! compute corresponding energy and ks matrix
958 196 : CALL ls_scf_dm_to_ks(qs_env, ls_scf_env, ls_scf_env%energy_init, iscf=0)
959 :
960 196 : CALL timestop(handle)
961 196 : END SUBROUTINE pao_aspc_guess_P
962 :
963 : ! **************************************************************************************************
964 : !> \brief Calculate the forces contributed by PAO
965 : !> \param qs_env ...
966 : !> \param ls_scf_env ...
967 : ! **************************************************************************************************
968 44 : SUBROUTINE pao_add_forces(qs_env, ls_scf_env)
969 : TYPE(qs_environment_type), POINTER :: qs_env
970 : TYPE(ls_scf_env_type), TARGET :: ls_scf_env
971 :
972 : CHARACTER(len=*), PARAMETER :: routineN = 'pao_add_forces'
973 :
974 : INTEGER :: handle, iatom, natoms
975 44 : REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: forces
976 : TYPE(mp_para_env_type), POINTER :: para_env
977 : TYPE(pao_env_type), POINTER :: pao
978 44 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
979 :
980 44 : CALL timeset(routineN, handle)
981 44 : pao => ls_scf_env%pao_env
982 :
983 44 : IF (pao%iw > 0) WRITE (pao%iw, *) "PAO| Adding forces."
984 :
985 44 : IF (pao%max_pao /= 0) THEN
986 20 : IF (pao%penalty_strength /= 0.0_dp) &
987 0 : CPABORT("PAO forces require PENALTY_STRENGTH or MAX_PAO set to zero")
988 20 : IF (pao%linpot_regu_strength /= 0.0_dp) &
989 0 : CPABORT("PAO forces require LINPOT_REGULARIZATION_STRENGTH or MAX_PAO set to zero")
990 20 : IF (pao%regularization /= 0.0_dp) &
991 0 : CPABORT("PAO forces require REGULARIZATION or MAX_PAO set to zero")
992 : END IF
993 :
994 : CALL get_qs_env(qs_env, &
995 : para_env=para_env, &
996 : particle_set=particle_set, &
997 44 : natom=natoms)
998 :
999 132 : ALLOCATE (forces(natoms, 3))
1000 44 : CALL pao_calc_AB(pao, qs_env, ls_scf_env, gradient=.TRUE., forces=forces) ! without penalty terms
1001 :
1002 44 : IF (SIZE(pao%ml_training_set) > 0) &
1003 18 : CALL pao_ml_forces(pao, qs_env, pao%matrix_G, forces)
1004 :
1005 44 : IF (ALLOCATED(pao%models)) &
1006 2 : CALL pao_model_forces(pao, qs_env, pao%matrix_G, forces)
1007 :
1008 44 : CALL para_env%sum(forces)
1009 150 : DO iatom = 1, natoms
1010 468 : particle_set(iatom)%f = particle_set(iatom)%f + forces(iatom, :)
1011 : END DO
1012 :
1013 44 : DEALLOCATE (forces)
1014 :
1015 44 : CALL timestop(handle)
1016 :
1017 44 : END SUBROUTINE pao_add_forces
1018 :
1019 : END MODULE pao_methods
|