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 Interface between ALMO SCF and QS
10 : !> \par History
11 : !> 2011.05 created [Rustam Z Khaliullin]
12 : !> \author Rustam Z Khaliullin
13 : ! **************************************************************************************************
14 : MODULE almo_scf_qs
15 : USE almo_scf_types, ONLY: almo_mat_dim_aobasis,&
16 : almo_mat_dim_occ,&
17 : almo_mat_dim_virt,&
18 : almo_mat_dim_virt_disc,&
19 : almo_mat_dim_virt_full,&
20 : almo_scf_env_type
21 : USE atomic_kind_types, ONLY: get_atomic_kind
22 : USE cell_types, ONLY: cell_type,&
23 : pbc
24 : USE cp_control_types, ONLY: dft_control_type
25 : USE cp_dbcsr_api, ONLY: &
26 : dbcsr_complete_redistribute, dbcsr_copy, dbcsr_create, dbcsr_desymmetrize, &
27 : dbcsr_distribution_get, dbcsr_distribution_new, dbcsr_distribution_release, &
28 : dbcsr_distribution_type, dbcsr_filter, dbcsr_finalize, dbcsr_get_block_p, dbcsr_get_info, &
29 : dbcsr_get_num_blocks, dbcsr_get_stored_coordinates, dbcsr_multiply, dbcsr_p_type, &
30 : dbcsr_put_block, dbcsr_release, dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry, &
31 : dbcsr_work_create
32 : USE cp_dbcsr_cp2k_link, ONLY: cp_dbcsr_alloc_block_from_nbl
33 : USE cp_dbcsr_operations, ONLY: dbcsr_allocate_matrix_set
34 : USE cp_fm_struct, ONLY: cp_fm_struct_create,&
35 : cp_fm_struct_release,&
36 : cp_fm_struct_type
37 : USE cp_fm_types, ONLY: cp_fm_create,&
38 : cp_fm_release,&
39 : cp_fm_type
40 : USE cp_log_handling, ONLY: cp_get_default_logger,&
41 : cp_logger_get_default_unit_nr,&
42 : cp_logger_type
43 : USE cp_units, ONLY: cp_unit_to_cp2k
44 : USE input_constants, ONLY: almo_constraint_ao_overlap,&
45 : almo_constraint_block_diagonal,&
46 : almo_constraint_distance,&
47 : almo_domain_layout_molecular,&
48 : almo_mat_distr_atomic,&
49 : almo_mat_distr_molecular,&
50 : do_bondparm_covalent,&
51 : do_bondparm_vdw
52 : USE kinds, ONLY: dp
53 : USE message_passing, ONLY: mp_comm_type
54 : USE molecule_types, ONLY: get_molecule_set_info,&
55 : molecule_type
56 : USE particle_types, ONLY: particle_type
57 : USE qs_energy_types, ONLY: qs_energy_type
58 : USE qs_environment_types, ONLY: get_qs_env,&
59 : qs_environment_type,&
60 : set_qs_env
61 : USE qs_ks_methods, ONLY: qs_ks_update_qs_env
62 : USE qs_ks_types, ONLY: qs_ks_did_change,&
63 : qs_ks_env_type,&
64 : set_ks_env
65 : USE qs_mo_types, ONLY: allocate_mo_set,&
66 : deallocate_mo_set,&
67 : init_mo_set,&
68 : mo_set_type
69 : USE qs_neighbor_list_types, ONLY: get_iterator_info,&
70 : neighbor_list_iterate,&
71 : neighbor_list_iterator_create,&
72 : neighbor_list_iterator_p_type,&
73 : neighbor_list_iterator_release,&
74 : neighbor_list_set_p_type
75 : USE qs_rho_methods, ONLY: qs_rho_update_rho
76 : USE qs_rho_types, ONLY: qs_rho_get,&
77 : qs_rho_type
78 : USE qs_scf_types, ONLY: qs_scf_env_type,&
79 : scf_env_create
80 : #include "./base/base_uses.f90"
81 :
82 : IMPLICIT NONE
83 :
84 : PRIVATE
85 :
86 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'almo_scf_qs'
87 :
88 : PUBLIC :: matrix_almo_create, &
89 : almo_scf_construct_quencher, &
90 : calculate_w_matrix_almo, &
91 : init_almo_ks_matrix_via_qs, &
92 : almo_scf_update_ks_energy, &
93 : construct_qs_mos, &
94 : matrix_qs_to_almo, &
95 : almo_dm_to_almo_ks, &
96 : almo_dm_to_qs_env
97 :
98 : CONTAINS
99 :
100 : ! **************************************************************************************************
101 : !> \brief create the ALMO matrix templates
102 : !> \param matrix_new ...
103 : !> \param matrix_qs ...
104 : !> \param almo_scf_env ...
105 : !> \param name_new ...
106 : !> \param size_keys ...
107 : !> \param symmetry_new ...
108 : !> \param spin_key ...
109 : !> \param init_domains ...
110 : !> \par History
111 : !> 2011.05 created [Rustam Z Khaliullin]
112 : !> \author Rustam Z Khaliullin
113 : ! **************************************************************************************************
114 3596 : SUBROUTINE matrix_almo_create(matrix_new, matrix_qs, almo_scf_env, &
115 : name_new, size_keys, symmetry_new, &
116 : spin_key, init_domains)
117 :
118 : TYPE(dbcsr_type) :: matrix_new, matrix_qs
119 : TYPE(almo_scf_env_type), INTENT(IN) :: almo_scf_env
120 : CHARACTER(len=*), INTENT(IN) :: name_new
121 : INTEGER, DIMENSION(2), INTENT(IN) :: size_keys
122 : CHARACTER, INTENT(IN) :: symmetry_new
123 : INTEGER, INTENT(IN) :: spin_key
124 : LOGICAL, INTENT(IN) :: init_domains
125 :
126 : CHARACTER(len=*), PARAMETER :: routineN = 'matrix_almo_create'
127 :
128 : INTEGER :: dimen, handle, hold, iatom, iblock_col, &
129 : iblock_row, imol, mynode, natoms, &
130 : nblkrows_tot, nlength, nmols, row
131 3596 : INTEGER, DIMENSION(:), POINTER :: blk_distr, blk_sizes, block_sizes_new, col_blk_size, &
132 3596 : col_distr_new, col_sizes_new, distr_new_array, row_blk_size, row_distr_new, row_sizes_new
133 : LOGICAL :: active, one_dim_is_mo, tr
134 3596 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: new_block
135 : TYPE(dbcsr_distribution_type) :: dist_new, dist_qs
136 :
137 : ! dimension size: AO, MO, etc
138 : ! almo_mat_dim_aobasis - no. of AOs,
139 : ! almo_mat_dim_occ - no. of occupied MOs
140 : ! almo_mat_dim_domains - no. of domains
141 : ! symmetry type: dbcsr_type_no_symmetry, dbcsr_type_symmetric,
142 : ! dbcsr_type_antisymmetric, dbcsr_type_hermitian, dbcsr_type_antihermitian
143 : ! (see dbcsr_lib/dbcsr_types.F for other values)
144 : ! spin_key: either 1 or 2 (0 is allowed for matrics in the AO basis)
145 : ! TYPE(dbcsr_iterator_type) :: iter
146 : ! REAL(KIND=dp), ALLOCATABLE, DIMENSION(:) :: allones
147 : !-----------------------------------------------------------------------
148 :
149 3596 : CALL timeset(routineN, handle)
150 :
151 : ! RZK-warning The structure of the matrices can be optimized:
152 : ! 1. Diagonal matrices must be distributed evenly over the processes.
153 : ! This can be achieved by distributing cpus: 012012-rows and 001122-cols
154 : ! block_diagonal_flag is introduced but not used
155 : ! 2. Multiplication of diagonally dominant matrices will be faster
156 : ! if the diagonal blocks are local to the same processes.
157 : ! 3. Systems of molecules of drastically different sizes might need
158 : ! better distribution.
159 :
160 : ! obtain distribution from the qs matrix - it might be useful
161 : ! to get the structure of the AO dimensions
162 3596 : CALL dbcsr_get_info(matrix_qs, distribution=dist_qs)
163 :
164 3596 : natoms = almo_scf_env%natoms
165 3596 : nmols = almo_scf_env%nmolecules
166 :
167 10788 : DO dimen = 1, 2 ! 1 - row, 2 - column dimension
168 :
169 : ! distribution pattern is the same for all matrix types (ao, occ, virt)
170 7192 : IF (dimen == 1) THEN !rows
171 3596 : CALL dbcsr_distribution_get(dist_qs, row_dist=blk_distr)
172 : ELSE !columns
173 3596 : CALL dbcsr_distribution_get(dist_qs, col_dist=blk_distr)
174 : END IF
175 :
176 7192 : IF (size_keys(dimen) == almo_mat_dim_aobasis) THEN ! this dimension is AO
177 :
178 : ! structure of an AO dimension can be copied from matrix_qs
179 2712 : CALL dbcsr_get_info(matrix_qs, row_blk_size=blk_sizes)
180 :
181 : ! atomic clustering of AOs
182 2712 : IF (almo_scf_env%mat_distr_aos == almo_mat_distr_atomic) THEN
183 0 : ALLOCATE (block_sizes_new(natoms), distr_new_array(natoms))
184 0 : block_sizes_new(:) = blk_sizes(:)
185 0 : distr_new_array(:) = blk_distr(:)
186 : ! molecular clustering of AOs
187 2712 : ELSE IF (almo_scf_env%mat_distr_aos == almo_mat_distr_molecular) THEN
188 10848 : ALLOCATE (block_sizes_new(nmols), distr_new_array(nmols))
189 20742 : block_sizes_new(:) = 0
190 47092 : DO iatom = 1, natoms
191 : block_sizes_new(almo_scf_env%domain_index_of_atom(iatom)) = &
192 : block_sizes_new(almo_scf_env%domain_index_of_atom(iatom)) + &
193 47092 : blk_sizes(iatom)
194 : END DO
195 20742 : DO imol = 1, nmols
196 : distr_new_array(imol) = &
197 20742 : blk_distr(almo_scf_env%first_atom_of_domain(imol))
198 : END DO
199 : ELSE
200 0 : CPABORT("Illegal distribution")
201 : END IF
202 :
203 : ELSE ! this dimension is not AO
204 :
205 : IF (size_keys(dimen) == almo_mat_dim_occ .OR. &
206 : size_keys(dimen) == almo_mat_dim_virt .OR. &
207 4480 : size_keys(dimen) == almo_mat_dim_virt_disc .OR. &
208 : size_keys(dimen) == almo_mat_dim_virt_full) THEN ! this dim is MO
209 :
210 : ! atomic clustering of MOs
211 4480 : IF (almo_scf_env%mat_distr_mos == almo_mat_distr_atomic) THEN
212 0 : nlength = natoms
213 0 : ALLOCATE (block_sizes_new(nlength))
214 0 : block_sizes_new(:) = 0
215 : IF (size_keys(dimen) == almo_mat_dim_occ) THEN
216 : ! currently distributing atomic distr of mos is not allowed
217 : ! RZK-warning define nocc_of_atom and nvirt_atom to implement it
218 : !block_sizes_new(:)=almo_scf_env%nocc_of_atom(:,spin_key)
219 : ELSE IF (size_keys(dimen) == almo_mat_dim_virt) THEN
220 : !block_sizes_new(:)=almo_scf_env%nvirt_of_atom(:,spin_key)
221 : END IF
222 : ! molecular clustering of MOs
223 4480 : ELSE IF (almo_scf_env%mat_distr_mos == almo_mat_distr_molecular) THEN
224 4480 : nlength = nmols
225 13440 : ALLOCATE (block_sizes_new(nlength))
226 4480 : IF (size_keys(dimen) == almo_mat_dim_occ) THEN
227 19240 : block_sizes_new(:) = almo_scf_env%nocc_of_domain(:, spin_key)
228 : ! Handle zero-electron fragments by adding one-orbital that
229 : ! must remain zero at all times
230 19240 : WHERE (block_sizes_new == 0) block_sizes_new = 1
231 1920 : ELSE IF (size_keys(dimen) == almo_mat_dim_virt_disc) THEN
232 0 : block_sizes_new(:) = almo_scf_env%nvirt_disc_of_domain(:, spin_key)
233 1920 : ELSE IF (size_keys(dimen) == almo_mat_dim_virt_full) THEN
234 5772 : block_sizes_new(:) = almo_scf_env%nvirt_full_of_domain(:, spin_key)
235 1152 : ELSE IF (size_keys(dimen) == almo_mat_dim_virt) THEN
236 8658 : block_sizes_new(:) = almo_scf_env%nvirt_of_domain(:, spin_key)
237 : END IF
238 : ELSE
239 0 : CPABORT("Illegal distribution")
240 : END IF
241 :
242 : ELSE
243 :
244 0 : CPABORT("Illegal dimension")
245 :
246 : END IF ! end choosing dim size (occ, virt)
247 :
248 : ! distribution for MOs is copied from AOs
249 13440 : ALLOCATE (distr_new_array(nlength))
250 : ! atomic clustering
251 4480 : IF (almo_scf_env%mat_distr_mos == almo_mat_distr_atomic) THEN
252 0 : distr_new_array(:) = blk_distr(:)
253 : ! molecular clustering
254 4480 : ELSE IF (almo_scf_env%mat_distr_mos == almo_mat_distr_molecular) THEN
255 33670 : DO imol = 1, nmols
256 : distr_new_array(imol) = &
257 33670 : blk_distr(almo_scf_env%first_atom_of_domain(imol))
258 : END DO
259 : END IF
260 : END IF ! end choosing dimension size (AOs vs .NOT.AOs)
261 :
262 : ! create final arrays
263 10788 : IF (dimen == 1) THEN !rows
264 3596 : row_sizes_new => block_sizes_new
265 3596 : row_distr_new => distr_new_array
266 : ELSE !columns
267 3596 : col_sizes_new => block_sizes_new
268 3596 : col_distr_new => distr_new_array
269 : END IF
270 : END DO ! both rows and columns are done
271 :
272 : ! Create the distribution
273 : CALL dbcsr_distribution_new(dist_new, template=dist_qs, &
274 : row_dist=row_distr_new, col_dist=col_distr_new, &
275 3596 : reuse_arrays=.TRUE.)
276 :
277 : ! Create the matrix
278 : CALL dbcsr_create(matrix_new, name_new, &
279 : dist_new, symmetry_new, &
280 3596 : row_sizes_new, col_sizes_new, reuse_arrays=.TRUE.)
281 3596 : CALL dbcsr_distribution_release(dist_new)
282 :
283 : ! fill out reqired blocks with 1.0_dp to tell the dbcsr library
284 : ! which blocks to keep
285 3596 : IF (init_domains) THEN
286 :
287 1426 : CALL dbcsr_distribution_get(dist_new, mynode=mynode)
288 1426 : CALL dbcsr_work_create(matrix_new, work_mutable=.TRUE.)
289 : CALL dbcsr_get_info(matrix_new, nblkrows_total=nblkrows_tot, &
290 1426 : row_blk_size=row_blk_size, col_blk_size=col_blk_size)
291 : ! start linear-scaling replacement:
292 : ! works only for molecular blocks AND molecular distributions
293 10870 : DO row = 1, nblkrows_tot
294 9444 : tr = .FALSE.
295 9444 : iblock_row = row
296 9444 : iblock_col = row
297 9444 : CALL dbcsr_get_stored_coordinates(matrix_new, iblock_row, iblock_col, hold)
298 :
299 10870 : IF (hold == mynode) THEN
300 :
301 14166 : active = .TRUE.
302 :
303 : one_dim_is_mo = .FALSE.
304 14166 : DO dimen = 1, 2 ! 1 - row, 2 - column dimension
305 14166 : IF (size_keys(dimen) == almo_mat_dim_occ) one_dim_is_mo = .TRUE.
306 : END DO
307 4722 : IF (one_dim_is_mo) THEN
308 1668 : IF (almo_scf_env%nocc_of_domain(row, spin_key) == 0) active = .FALSE.
309 : END IF
310 :
311 4722 : one_dim_is_mo = .FALSE.
312 14166 : DO dimen = 1, 2
313 14166 : IF (size_keys(dimen) == almo_mat_dim_virt) one_dim_is_mo = .TRUE.
314 : END DO
315 4722 : IF (one_dim_is_mo) THEN
316 417 : IF (almo_scf_env%nvirt_of_domain(row, spin_key) == 0) active = .FALSE.
317 : END IF
318 :
319 4722 : one_dim_is_mo = .FALSE.
320 14166 : DO dimen = 1, 2
321 14166 : IF (size_keys(dimen) == almo_mat_dim_virt_disc) one_dim_is_mo = .TRUE.
322 : END DO
323 4722 : IF (one_dim_is_mo) THEN
324 0 : IF (almo_scf_env%nvirt_disc_of_domain(row, spin_key) == 0) active = .FALSE.
325 : END IF
326 :
327 4722 : one_dim_is_mo = .FALSE.
328 14166 : DO dimen = 1, 2
329 14166 : IF (size_keys(dimen) == almo_mat_dim_virt_full) one_dim_is_mo = .TRUE.
330 : END DO
331 4722 : IF (one_dim_is_mo) THEN
332 417 : IF (almo_scf_env%nvirt_full_of_domain(row, spin_key) == 0) active = .FALSE.
333 : END IF
334 :
335 4688 : IF (active) THEN
336 17592 : ALLOCATE (new_block(row_blk_size(iblock_row), col_blk_size(iblock_col)))
337 840230 : new_block(:, :) = 1.0_dp
338 4398 : CALL dbcsr_put_block(matrix_new, iblock_row, iblock_col, new_block)
339 4398 : DEALLOCATE (new_block)
340 : END IF
341 :
342 : END IF ! mynode
343 : END DO
344 : ! end lnear-scaling replacement
345 :
346 : END IF ! init_domains
347 :
348 3596 : CALL dbcsr_finalize(matrix_new)
349 :
350 3596 : CALL timestop(handle)
351 :
352 7192 : END SUBROUTINE matrix_almo_create
353 :
354 : ! **************************************************************************************************
355 : !> \brief convert between two types of matrices: QS style to ALMO style
356 : !> \param matrix_qs ...
357 : !> \param matrix_almo ...
358 : !> \param mat_distr_aos ...
359 : !> \par History
360 : !> 2011.06 created [Rustam Z Khaliullin]
361 : !> \author Rustam Z Khaliullin
362 : ! **************************************************************************************************
363 2080 : SUBROUTINE matrix_qs_to_almo(matrix_qs, matrix_almo, mat_distr_aos)
364 :
365 : TYPE(dbcsr_type) :: matrix_qs, matrix_almo
366 : INTEGER :: mat_distr_aos
367 :
368 : CHARACTER(len=*), PARAMETER :: routineN = 'matrix_qs_to_almo'
369 :
370 : INTEGER :: handle
371 : TYPE(dbcsr_type) :: matrix_qs_nosym
372 :
373 2080 : CALL timeset(routineN, handle)
374 : !RZK-warning if it's not a N(AO)xN(AO) matrix then stop
375 :
376 2080 : SELECT CASE (mat_distr_aos)
377 : CASE (almo_mat_distr_atomic)
378 : ! automatic data_type conversion
379 0 : CALL dbcsr_copy(matrix_almo, matrix_qs)
380 : CASE (almo_mat_distr_molecular)
381 : ! desymmetrize the qs matrix
382 2080 : CALL dbcsr_create(matrix_qs_nosym, template=matrix_qs, matrix_type=dbcsr_type_no_symmetry)
383 2080 : CALL dbcsr_desymmetrize(matrix_qs, matrix_qs_nosym)
384 :
385 : ! perform the magic complete_redistribute
386 : ! before calling complete_redistribute set all blocks to zero
387 : ! otherwise the non-zero elements of the redistributed matrix,
388 : ! which are in zero-blocks of the original matrix, will remain
389 : ! in the final redistributed matrix. this is a bug in
390 : ! complete_redistribute. RZK-warning it should be later corrected by calling
391 : ! dbcsr_set to 0.0 from within complete_redistribute
392 2080 : CALL dbcsr_set(matrix_almo, 0.0_dp)
393 2080 : CALL dbcsr_complete_redistribute(matrix_qs_nosym, matrix_almo)
394 2080 : CALL dbcsr_release(matrix_qs_nosym)
395 :
396 : CASE DEFAULT
397 2080 : CPABORT("Unknown mat_distr_aos for matrix_qs_to_almo")
398 : END SELECT
399 :
400 2080 : CALL timestop(handle)
401 :
402 2080 : END SUBROUTINE matrix_qs_to_almo
403 :
404 : ! **************************************************************************************************
405 : !> \brief convert between two types of matrices: ALMO style to QS style
406 : !> \param matrix_almo ...
407 : !> \param matrix_qs ...
408 : !> \param mat_distr_aos ...
409 : !> \par History
410 : !> 2011.06 created [Rustam Z Khaliullin]
411 : !> \author Rustam Z Khaliullin
412 : ! **************************************************************************************************
413 1862 : SUBROUTINE matrix_almo_to_qs(matrix_almo, matrix_qs, mat_distr_aos)
414 : TYPE(dbcsr_type) :: matrix_almo, matrix_qs
415 : INTEGER, INTENT(IN) :: mat_distr_aos
416 :
417 : CHARACTER(len=*), PARAMETER :: routineN = 'matrix_almo_to_qs'
418 :
419 : INTEGER :: handle
420 : TYPE(dbcsr_type) :: matrix_almo_redist
421 :
422 1862 : CALL timeset(routineN, handle)
423 : ! RZK-warning if it's not a N(AO)xN(AO) matrix then stop
424 :
425 1862 : SELECT CASE (mat_distr_aos)
426 : CASE (almo_mat_distr_atomic)
427 0 : CALL dbcsr_copy(matrix_qs, matrix_almo, keep_sparsity=.TRUE.)
428 : CASE (almo_mat_distr_molecular)
429 1862 : CALL dbcsr_create(matrix_almo_redist, template=matrix_qs)
430 1862 : CALL dbcsr_complete_redistribute(matrix_almo, matrix_almo_redist)
431 1862 : CALL dbcsr_set(matrix_qs, 0.0_dp)
432 1862 : CALL dbcsr_copy(matrix_qs, matrix_almo_redist, keep_sparsity=.TRUE.)
433 1862 : CALL dbcsr_release(matrix_almo_redist)
434 : CASE DEFAULT
435 1862 : CPABORT("Unknown mat_distr_aos for matrix_almo_to_qs")
436 : END SELECT
437 :
438 1862 : CALL timestop(handle)
439 :
440 1862 : END SUBROUTINE matrix_almo_to_qs
441 :
442 : ! **************************************************************************************************
443 : !> \brief Initialization of the QS and ALMO KS matrix
444 : !> \param qs_env ...
445 : !> \param matrix_ks ...
446 : !> \param mat_distr_aos ...
447 : !> \param eps_filter ...
448 : !> \par History
449 : !> 2011.05 created [Rustam Z Khaliullin]
450 : !> \author Rustam Z Khaliullin
451 : ! **************************************************************************************************
452 122 : SUBROUTINE init_almo_ks_matrix_via_qs(qs_env, matrix_ks, mat_distr_aos, eps_filter)
453 :
454 : TYPE(qs_environment_type), POINTER :: qs_env
455 : TYPE(dbcsr_type), DIMENSION(:) :: matrix_ks
456 : INTEGER :: mat_distr_aos
457 : REAL(KIND=dp) :: eps_filter
458 :
459 : CHARACTER(len=*), PARAMETER :: routineN = 'init_almo_ks_matrix_via_qs'
460 :
461 : INTEGER :: handle, ispin, nspin
462 122 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_qs_ks, matrix_qs_s
463 : TYPE(dft_control_type), POINTER :: dft_control
464 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
465 122 : POINTER :: sab_orb
466 : TYPE(qs_ks_env_type), POINTER :: ks_env
467 :
468 122 : CALL timeset(routineN, handle)
469 :
470 122 : NULLIFY (sab_orb)
471 :
472 : ! get basic quantities from the qs_env
473 : CALL get_qs_env(qs_env, &
474 : dft_control=dft_control, &
475 : matrix_s=matrix_qs_s, &
476 : matrix_ks=matrix_qs_ks, &
477 : ks_env=ks_env, &
478 122 : sab_orb=sab_orb)
479 :
480 122 : nspin = dft_control%nspins
481 :
482 : ! create matrix_ks in the QS env if necessary
483 122 : IF (.NOT. ASSOCIATED(matrix_qs_ks)) THEN
484 0 : CALL dbcsr_allocate_matrix_set(matrix_qs_ks, nspin)
485 0 : DO ispin = 1, nspin
486 0 : ALLOCATE (matrix_qs_ks(ispin)%matrix)
487 : CALL dbcsr_create(matrix_qs_ks(ispin)%matrix, &
488 0 : template=matrix_qs_s(1)%matrix)
489 0 : CALL cp_dbcsr_alloc_block_from_nbl(matrix_qs_ks(ispin)%matrix, sab_orb)
490 0 : CALL dbcsr_set(matrix_qs_ks(ispin)%matrix, 0.0_dp)
491 : END DO
492 0 : CALL set_ks_env(ks_env, matrix_ks=matrix_qs_ks)
493 : END IF
494 :
495 : ! copy to ALMO
496 250 : DO ispin = 1, nspin
497 128 : CALL matrix_qs_to_almo(matrix_qs_ks(ispin)%matrix, matrix_ks(ispin), mat_distr_aos)
498 250 : CALL dbcsr_filter(matrix_ks(ispin), eps_filter)
499 : END DO
500 :
501 122 : CALL timestop(handle)
502 :
503 122 : END SUBROUTINE init_almo_ks_matrix_via_qs
504 :
505 : ! **************************************************************************************************
506 : !> \brief Create MOs in the QS env to be able to return ALMOs to QS
507 : !> \param qs_env ...
508 : !> \param almo_scf_env ...
509 : !> \par History
510 : !> 2016.12 created [Yifei Shi]
511 : !> \author Yifei Shi
512 : ! **************************************************************************************************
513 366 : SUBROUTINE construct_qs_mos(qs_env, almo_scf_env)
514 :
515 : TYPE(qs_environment_type), POINTER :: qs_env
516 : TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
517 :
518 : CHARACTER(len=*), PARAMETER :: routineN = 'construct_qs_mos'
519 :
520 : INTEGER :: handle, ispin, ncol_fm, nrow_fm
521 : TYPE(cp_fm_struct_type), POINTER :: fm_struct_tmp
522 : TYPE(cp_fm_type) :: mo_fm_copy
523 : TYPE(dft_control_type), POINTER :: dft_control
524 122 : TYPE(mo_set_type), DIMENSION(:), POINTER :: mos
525 : TYPE(qs_scf_env_type), POINTER :: scf_env
526 :
527 122 : CALL timeset(routineN, handle)
528 :
529 : ! create and init scf_env (this is necessary to return MOs to qs)
530 122 : NULLIFY (mos, fm_struct_tmp, scf_env)
531 122 : ALLOCATE (scf_env)
532 122 : CALL scf_env_create(scf_env)
533 :
534 : !CALL qs_scf_env_initialize(qs_env, scf_env)
535 122 : CALL set_qs_env(qs_env, scf_env=scf_env)
536 122 : CALL get_qs_env(qs_env, dft_control=dft_control, mos=mos)
537 :
538 122 : CALL dbcsr_get_info(almo_scf_env%matrix_t(1), nfullrows_total=nrow_fm, nfullcols_total=ncol_fm)
539 :
540 : ! allocate and init mo_set
541 250 : DO ispin = 1, almo_scf_env%nspins
542 128 : CALL dbcsr_get_info(almo_scf_env%matrix_t(ispin), nfullrows_total=nrow_fm, nfullcols_total=ncol_fm)
543 :
544 : ! Currently only fm version of mo_set is usable.
545 : ! First transform the matrix_t to fm version
546 : ! Empty the containers to prevent memory leaks
547 128 : CALL deallocate_mo_set(mos(ispin))
548 :
549 128 : IF (almo_scf_env%nspins == 1) THEN
550 : CALL allocate_mo_set(mo_set=mos(ispin), &
551 : nao=nrow_fm, &
552 : nmo=ncol_fm, &
553 : nelectron=almo_scf_env%nelectrons_total, &
554 : n_el_f=REAL(almo_scf_env%nelectrons_total, dp), &
555 : maxocc=2.0_dp, &
556 116 : flexible_electron_count=dft_control%relax_multiplicity)
557 12 : ELSE IF (almo_scf_env%nspins == 2) THEN
558 : CALL allocate_mo_set(mo_set=mos(ispin), &
559 : nao=nrow_fm, &
560 : nmo=ncol_fm, &
561 : nelectron=SUM(almo_scf_env%nocc_of_domain(:, ispin)), &
562 : n_el_f=REAL(SUM(almo_scf_env%nocc_of_domain(:, ispin)), dp), &
563 : maxocc=1.0_dp, &
564 60 : flexible_electron_count=dft_control%relax_multiplicity)
565 : END IF
566 :
567 : CALL cp_fm_struct_create(fm_struct_tmp, nrow_global=nrow_fm, ncol_global=ncol_fm, &
568 : context=almo_scf_env%blacs_env, &
569 128 : para_env=almo_scf_env%para_env)
570 :
571 128 : CALL cp_fm_create(mo_fm_copy, fm_struct_tmp, name="t_orthogonal_converted_to_fm")
572 128 : CALL cp_fm_struct_release(fm_struct_tmp)
573 : !CALL copy_dbcsr_to_fm(almo_scf_env%matrix_t(ispin), mo_fm_copy)
574 :
575 128 : CALL init_mo_set(mos(ispin), fm_ref=mo_fm_copy, name='fm_mo')
576 :
577 506 : CALL cp_fm_release(mo_fm_copy)
578 :
579 : END DO
580 :
581 122 : CALL timestop(handle)
582 :
583 122 : END SUBROUTINE construct_qs_mos
584 :
585 : ! **************************************************************************************************
586 : !> \brief return density matrix to the qs_env
587 : !> \param qs_env ...
588 : !> \param matrix_p ...
589 : !> \param mat_distr_aos ...
590 : !> \par History
591 : !> 2011.05 created [Rustam Z Khaliullin]
592 : !> \author Rustam Z Khaliullin
593 : ! **************************************************************************************************
594 1778 : SUBROUTINE almo_dm_to_qs_env(qs_env, matrix_p, mat_distr_aos)
595 : TYPE(qs_environment_type), POINTER :: qs_env
596 : TYPE(dbcsr_type), DIMENSION(:) :: matrix_p
597 : INTEGER, INTENT(IN) :: mat_distr_aos
598 :
599 : CHARACTER(len=*), PARAMETER :: routineN = 'almo_dm_to_qs_env'
600 :
601 : INTEGER :: handle, ispin, nspins
602 1778 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: rho_ao
603 : TYPE(qs_rho_type), POINTER :: rho
604 :
605 1778 : CALL timeset(routineN, handle)
606 :
607 1778 : NULLIFY (rho, rho_ao)
608 1778 : nspins = SIZE(matrix_p)
609 1778 : CALL get_qs_env(qs_env, rho=rho)
610 1778 : CALL qs_rho_get(rho, rho_ao=rho_ao)
611 :
612 : ! set the new density matrix
613 3574 : DO ispin = 1, nspins
614 : CALL matrix_almo_to_qs(matrix_p(ispin), &
615 : rho_ao(ispin)%matrix, &
616 3574 : mat_distr_aos)
617 : END DO
618 1778 : CALL qs_rho_update_rho(rho, qs_env=qs_env)
619 1778 : CALL qs_ks_did_change(qs_env%ks_env, rho_changed=.TRUE.)
620 :
621 1778 : CALL timestop(handle)
622 :
623 1778 : END SUBROUTINE almo_dm_to_qs_env
624 :
625 : ! **************************************************************************************************
626 : !> \brief uses the ALMO density matrix
627 : !> to compute KS matrix (inside QS environment) and the new energy
628 : !> \param qs_env ...
629 : !> \param matrix_p ...
630 : !> \param energy_total ...
631 : !> \param mat_distr_aos ...
632 : !> \param smear ...
633 : !> \param kTS_sum ...
634 : !> \par History
635 : !> 2011.05 created [Rustam Z Khaliullin]
636 : !> 2018.09 smearing support [Ruben Staub]
637 : !> \author Rustam Z Khaliullin
638 : ! **************************************************************************************************
639 1752 : SUBROUTINE almo_dm_to_qs_ks(qs_env, matrix_p, energy_total, mat_distr_aos, smear, kTS_sum)
640 : TYPE(qs_environment_type), POINTER :: qs_env
641 : TYPE(dbcsr_type), DIMENSION(:) :: matrix_p
642 : REAL(KIND=dp) :: energy_total
643 : INTEGER, INTENT(IN) :: mat_distr_aos
644 : LOGICAL, INTENT(IN), OPTIONAL :: smear
645 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: kTS_sum
646 :
647 : CHARACTER(len=*), PARAMETER :: routineN = 'almo_dm_to_qs_ks'
648 :
649 : INTEGER :: handle
650 : LOGICAL :: smearing
651 : REAL(KIND=dp) :: entropic_term
652 : TYPE(qs_energy_type), POINTER :: energy
653 :
654 1752 : CALL timeset(routineN, handle)
655 :
656 1752 : IF (PRESENT(smear)) THEN
657 1752 : smearing = smear
658 : ELSE
659 : smearing = .FALSE.
660 : END IF
661 :
662 1752 : IF (PRESENT(kTS_sum)) THEN
663 1752 : entropic_term = kTS_sum
664 : ELSE
665 : entropic_term = 0.0_dp
666 : END IF
667 :
668 1752 : NULLIFY (energy)
669 1752 : CALL get_qs_env(qs_env, energy=energy)
670 1752 : CALL almo_dm_to_qs_env(qs_env, matrix_p, mat_distr_aos)
671 : CALL qs_ks_update_qs_env(qs_env, calculate_forces=.FALSE., just_energy=.FALSE., &
672 1752 : print_active=.TRUE.)
673 :
674 : !! Add electronic entropy contribution if smearing is requested
675 : !! Previous QS entropy is replaced by the sum of the entropy for each spin
676 1752 : IF (smearing) THEN
677 20 : energy%total = energy%total - energy%kTS + entropic_term
678 : END IF
679 :
680 1752 : energy_total = energy%total
681 :
682 1752 : CALL timestop(handle)
683 :
684 1752 : END SUBROUTINE almo_dm_to_qs_ks
685 :
686 : ! **************************************************************************************************
687 : !> \brief uses the ALMO density matrix
688 : !> to compute ALMO KS matrix and the new energy
689 : !> \param qs_env ...
690 : !> \param matrix_p ...
691 : !> \param matrix_ks ...
692 : !> \param energy_total ...
693 : !> \param eps_filter ...
694 : !> \param mat_distr_aos ...
695 : !> \param smear ...
696 : !> \param kTS_sum ...
697 : !> \par History
698 : !> 2011.05 created [Rustam Z Khaliullin]
699 : !> 2018.09 smearing support [Ruben Staub]
700 : !> \author Rustam Z Khaliullin
701 : ! **************************************************************************************************
702 1752 : SUBROUTINE almo_dm_to_almo_ks(qs_env, matrix_p, matrix_ks, energy_total, eps_filter, &
703 : mat_distr_aos, smear, kTS_sum)
704 :
705 : TYPE(qs_environment_type), POINTER :: qs_env
706 : TYPE(dbcsr_type), DIMENSION(:) :: matrix_p, matrix_ks
707 : REAL(KIND=dp) :: energy_total, eps_filter
708 : INTEGER, INTENT(IN) :: mat_distr_aos
709 : LOGICAL, INTENT(IN), OPTIONAL :: smear
710 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: kTS_sum
711 :
712 : CHARACTER(len=*), PARAMETER :: routineN = 'almo_dm_to_almo_ks'
713 :
714 : INTEGER :: handle, ispin, nspins
715 : LOGICAL :: smearing
716 : REAL(KIND=dp) :: entropic_term
717 1752 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_qs_ks
718 :
719 1752 : CALL timeset(routineN, handle)
720 :
721 1752 : IF (PRESENT(smear)) THEN
722 470 : smearing = smear
723 : ELSE
724 1282 : smearing = .FALSE.
725 : END IF
726 :
727 1752 : IF (PRESENT(kTS_sum)) THEN
728 470 : entropic_term = kTS_sum
729 : ELSE
730 1282 : entropic_term = 0.0_dp
731 : END IF
732 :
733 : ! update KS matrix in the QS env
734 : CALL almo_dm_to_qs_ks(qs_env, matrix_p, energy_total, mat_distr_aos, &
735 : smear=smearing, &
736 1752 : kTS_sum=entropic_term)
737 :
738 1752 : nspins = SIZE(matrix_ks)
739 :
740 : ! get KS matrix from the QS env and convert to the ALMO format
741 1752 : CALL get_qs_env(qs_env, matrix_ks=matrix_qs_ks)
742 3522 : DO ispin = 1, nspins
743 1770 : CALL matrix_qs_to_almo(matrix_qs_ks(ispin)%matrix, matrix_ks(ispin), mat_distr_aos)
744 3522 : CALL dbcsr_filter(matrix_ks(ispin), eps_filter)
745 : END DO
746 :
747 1752 : CALL timestop(handle)
748 :
749 1752 : END SUBROUTINE almo_dm_to_almo_ks
750 :
751 : ! **************************************************************************************************
752 : !> \brief update qs_env total energy
753 : !> \param qs_env ...
754 : !> \param energy ...
755 : !> \param energy_singles_corr ...
756 : !> \par History
757 : !> 2013.03 created [Rustam Z Khaliullin]
758 : !> \author Rustam Z Khaliullin
759 : ! **************************************************************************************************
760 112 : SUBROUTINE almo_scf_update_ks_energy(qs_env, energy, energy_singles_corr)
761 :
762 : TYPE(qs_environment_type), POINTER :: qs_env
763 : REAL(KIND=dp), INTENT(IN), OPTIONAL :: energy, energy_singles_corr
764 :
765 : TYPE(qs_energy_type), POINTER :: qs_energy
766 :
767 112 : CALL get_qs_env(qs_env, energy=qs_energy)
768 :
769 112 : IF (PRESENT(energy_singles_corr)) THEN
770 26 : qs_energy%singles_corr = energy_singles_corr
771 : ELSE
772 86 : qs_energy%singles_corr = 0.0_dp
773 : END IF
774 :
775 112 : IF (PRESENT(energy)) THEN
776 112 : qs_energy%total = energy
777 : END IF
778 :
779 112 : qs_energy%total = qs_energy%total + qs_energy%singles_corr
780 :
781 112 : END SUBROUTINE almo_scf_update_ks_energy
782 :
783 : ! **************************************************************************************************
784 : !> \brief Creates the matrix that imposes absolute locality on MOs
785 : !> \param qs_env ...
786 : !> \param almo_scf_env ...
787 : !> \par History
788 : !> 2011.11 created [Rustam Z. Khaliullin]
789 : !> \author Rustam Z. Khaliullin
790 : ! **************************************************************************************************
791 122 : SUBROUTINE almo_scf_construct_quencher(qs_env, almo_scf_env)
792 :
793 : TYPE(qs_environment_type), POINTER :: qs_env
794 : TYPE(almo_scf_env_type), INTENT(INOUT) :: almo_scf_env
795 :
796 : CHARACTER(len=*), PARAMETER :: routineN = 'almo_scf_construct_quencher'
797 :
798 : CHARACTER :: sym
799 : INTEGER :: col, contact_atom_1, contact_atom_2, domain_col, domain_map_local_entries, &
800 : domain_row, global_entries, global_list_length, grid1, GroupID, handle, hold, iatom, &
801 : iatom2, iblock_col, iblock_row, idomain, idomain2, ientry, igrid, ineig, ineighbor, &
802 : iNode, inode2, ipair, ispin, jatom, jatom2, jdomain2, local_list_length, &
803 : max_domain_neighbors, max_neig, mynode, nblkcols_tot, nblkrows_tot, nblks, ndomains, &
804 : neig_temp, nnode2, nNodes, row, unit_nr
805 122 : INTEGER, ALLOCATABLE, DIMENSION(:) :: current_number_neighbors, domain_entries_cpu, &
806 122 : domain_map_global, domain_map_local, first_atom_of_molecule, global_list, &
807 122 : last_atom_of_molecule, list_length_cpu, list_offset_cpu, local_list, offset_for_cpu
808 122 : INTEGER, ALLOCATABLE, DIMENSION(:, :) :: domain_grid, domain_neighbor_list, &
809 122 : domain_neighbor_list_excessive
810 122 : INTEGER, DIMENSION(:), POINTER :: col_blk_size, row_blk_size
811 : LOGICAL :: already_listed, block_active, &
812 : delayed_increment, found, &
813 : max_neig_fails, tr
814 : REAL(KIND=dp) :: contact1_radius, contact2_radius, &
815 : distance, distance_squared, overlap, &
816 : r0, r1, s0, s1, trial_distance_squared
817 122 : REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :) :: new_block
818 : REAL(KIND=dp), DIMENSION(3) :: rab
819 122 : REAL(KIND=dp), DIMENSION(:, :), POINTER :: p_old_block
820 : TYPE(cell_type), POINTER :: cell
821 : TYPE(cp_logger_type), POINTER :: logger
822 : TYPE(dbcsr_distribution_type) :: dist
823 122 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_s
824 : TYPE(dbcsr_type) :: matrix_s_sym
825 122 : TYPE(molecule_type), DIMENSION(:), POINTER :: molecule_set
826 : TYPE(mp_comm_type) :: group
827 : TYPE(neighbor_list_iterator_p_type), &
828 122 : DIMENSION(:), POINTER :: nl_iterator, nl_iterator2
829 : TYPE(neighbor_list_set_p_type), DIMENSION(:), &
830 122 : POINTER :: sab_almo
831 122 : TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
832 :
833 122 : CALL timeset(routineN, handle)
834 :
835 : ! get a useful output_unit
836 122 : logger => cp_get_default_logger()
837 122 : IF (logger%para_env%is_source()) THEN
838 61 : unit_nr = cp_logger_get_default_unit_nr(logger, local=.TRUE.)
839 : ELSE
840 : unit_nr = -1
841 : END IF
842 :
843 122 : ndomains = almo_scf_env%ndomains
844 :
845 : CALL get_qs_env(qs_env=qs_env, &
846 : particle_set=particle_set, &
847 : molecule_set=molecule_set, &
848 : cell=cell, &
849 : matrix_s=matrix_s, &
850 122 : sab_almo=sab_almo)
851 :
852 : ! if we are dealing with molecules get info about them
853 122 : IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular .OR. &
854 : almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
855 366 : ALLOCATE (first_atom_of_molecule(almo_scf_env%nmolecules))
856 244 : ALLOCATE (last_atom_of_molecule(almo_scf_env%nmolecules))
857 : CALL get_molecule_set_info(molecule_set, &
858 : mol_to_first_atom=first_atom_of_molecule, &
859 122 : mol_to_last_atom=last_atom_of_molecule)
860 : END IF
861 :
862 : ! create a symmetrized copy of the ao overlap
863 : CALL dbcsr_create(matrix_s_sym, &
864 : template=almo_scf_env%matrix_s(1), &
865 122 : matrix_type=dbcsr_type_no_symmetry)
866 : CALL dbcsr_get_info(almo_scf_env%matrix_s(1), &
867 122 : matrix_type=sym)
868 122 : IF (sym == dbcsr_type_no_symmetry) THEN
869 0 : CALL dbcsr_copy(matrix_s_sym, almo_scf_env%matrix_s(1))
870 : ELSE
871 : CALL dbcsr_desymmetrize(almo_scf_env%matrix_s(1), &
872 122 : matrix_s_sym)
873 : END IF
874 :
875 494 : ALLOCATE (almo_scf_env%quench_t(almo_scf_env%nspins))
876 494 : ALLOCATE (almo_scf_env%domain_map(almo_scf_env%nspins))
877 :
878 250 : DO ispin = 1, almo_scf_env%nspins
879 :
880 : ! create the sparsity template for the occupied orbitals
881 : CALL matrix_almo_create(matrix_new=almo_scf_env%quench_t(ispin), &
882 : matrix_qs=matrix_s(1)%matrix, &
883 : almo_scf_env=almo_scf_env, &
884 : name_new="T_QUENCHER", &
885 : size_keys=[almo_mat_dim_aobasis, almo_mat_dim_occ], &
886 : symmetry_new=dbcsr_type_no_symmetry, &
887 : spin_key=ispin, &
888 128 : init_domains=.FALSE.)
889 :
890 : ! initialize distance quencher
891 128 : CALL dbcsr_work_create(almo_scf_env%quench_t(ispin), work_mutable=.TRUE.)
892 : CALL dbcsr_get_info(almo_scf_env%quench_t(ispin), distribution=dist, &
893 128 : nblkrows_total=nblkrows_tot, nblkcols_total=nblkcols_tot)
894 128 : CALL dbcsr_distribution_get(dist, numnodes=nNodes, group=GroupID, mynode=mynode)
895 128 : CALL group%set_handle(groupid)
896 :
897 : ! create global atom neighbor list from the local lists
898 : ! first, calculate number of local pairs
899 128 : local_list_length = 0
900 128 : CALL neighbor_list_iterator_create(nl_iterator, sab_almo)
901 39611 : DO WHILE (neighbor_list_iterate(nl_iterator) == 0)
902 : ! nnode - total number of neighbors for iatom
903 : ! inode - current neighbor count
904 : CALL get_iterator_info(nl_iterator, &
905 39483 : iatom=iatom2, jatom=jatom2, inode=inode2, nnode=nnode2)
906 39611 : IF (inode2 == 1) THEN
907 2049 : local_list_length = local_list_length + nnode2
908 : END IF
909 : END DO
910 128 : CALL neighbor_list_iterator_release(nl_iterator)
911 :
912 : ! second, extract the local list to an array
913 383 : ALLOCATE (local_list(2*local_list_length))
914 128 : local_list(:) = 0
915 128 : local_list_length = 0
916 128 : CALL neighbor_list_iterator_create(nl_iterator2, sab_almo)
917 39611 : DO WHILE (neighbor_list_iterate(nl_iterator2) == 0)
918 : CALL get_iterator_info(nl_iterator2, &
919 39483 : iatom=iatom2, jatom=jatom2)
920 39483 : local_list(2*local_list_length + 1) = iatom2
921 39483 : local_list(2*local_list_length + 2) = jatom2
922 39483 : local_list_length = local_list_length + 1
923 : END DO ! end loop over pairs of atoms
924 128 : CALL neighbor_list_iterator_release(nl_iterator2)
925 :
926 : ! third, communicate local length to the other nodes
927 512 : ALLOCATE (list_length_cpu(nNodes), list_offset_cpu(nNodes))
928 128 : CALL group%allgather(2*local_list_length, list_length_cpu)
929 :
930 : ! fourth, create a global list
931 128 : list_offset_cpu(1) = 0
932 256 : DO iNode = 2, nNodes
933 : list_offset_cpu(iNode) = list_offset_cpu(iNode - 1) + &
934 256 : list_length_cpu(iNode - 1)
935 : END DO
936 128 : global_list_length = list_offset_cpu(nNodes) + list_length_cpu(nNodes)
937 :
938 : ! fifth, communicate all list data
939 384 : ALLOCATE (global_list(global_list_length))
940 : CALL group%allgatherv(local_list, global_list, &
941 128 : list_length_cpu, list_offset_cpu)
942 128 : DEALLOCATE (list_length_cpu, list_offset_cpu)
943 128 : DEALLOCATE (local_list)
944 :
945 : ! calculate maximum number of atoms surrounding the domain
946 384 : ALLOCATE (current_number_neighbors(almo_scf_env%ndomains))
947 128 : current_number_neighbors(:) = 0
948 128 : global_list_length = global_list_length/2
949 79094 : DO ipair = 1, global_list_length
950 78966 : iatom2 = global_list(2*(ipair - 1) + 1)
951 78966 : jatom2 = global_list(2*(ipair - 1) + 2)
952 78966 : idomain2 = almo_scf_env%domain_index_of_atom(iatom2)
953 78966 : jdomain2 = almo_scf_env%domain_index_of_atom(jatom2)
954 : ! add to the list
955 78966 : current_number_neighbors(idomain2) = current_number_neighbors(idomain2) + 1
956 : ! add j,i with i,j
957 79094 : IF (idomain2 /= jdomain2) THEN
958 63144 : current_number_neighbors(jdomain2) = current_number_neighbors(jdomain2) + 1
959 : END IF
960 : END DO
961 962 : max_domain_neighbors = MAXVAL(current_number_neighbors)
962 :
963 : ! use the global atom neighbor list to create a global domain neighbor list
964 512 : ALLOCATE (domain_neighbor_list_excessive(ndomains, max_domain_neighbors))
965 962 : current_number_neighbors(:) = 1
966 962 : DO ipair = 1, ndomains
967 962 : domain_neighbor_list_excessive(ipair, 1) = ipair
968 : END DO
969 79094 : DO ipair = 1, global_list_length
970 78966 : iatom2 = global_list(2*(ipair - 1) + 1)
971 78966 : jatom2 = global_list(2*(ipair - 1) + 2)
972 78966 : idomain2 = almo_scf_env%domain_index_of_atom(iatom2)
973 78966 : jdomain2 = almo_scf_env%domain_index_of_atom(jatom2)
974 78966 : already_listed = .FALSE.
975 325938 : DO ineighbor = 1, current_number_neighbors(idomain2)
976 325938 : IF (domain_neighbor_list_excessive(idomain2, ineighbor) == jdomain2) THEN
977 : already_listed = .TRUE.
978 : EXIT
979 : END IF
980 : END DO
981 79094 : IF (.NOT. already_listed) THEN
982 : ! add to the list
983 2722 : current_number_neighbors(idomain2) = current_number_neighbors(idomain2) + 1
984 2722 : domain_neighbor_list_excessive(idomain2, current_number_neighbors(idomain2)) = jdomain2
985 : ! add j,i with i,j
986 2722 : IF (idomain2 /= jdomain2) THEN
987 2722 : current_number_neighbors(jdomain2) = current_number_neighbors(jdomain2) + 1
988 2722 : domain_neighbor_list_excessive(jdomain2, current_number_neighbors(jdomain2)) = idomain2
989 : END IF
990 : END IF
991 : END DO ! end loop over pairs of atoms
992 128 : DEALLOCATE (global_list)
993 :
994 962 : max_domain_neighbors = MAXVAL(current_number_neighbors)
995 512 : ALLOCATE (domain_neighbor_list(ndomains, max_domain_neighbors))
996 128 : domain_neighbor_list(:, :) = 0
997 7248 : domain_neighbor_list(:, :) = domain_neighbor_list_excessive(:, 1:max_domain_neighbors)
998 128 : DEALLOCATE (domain_neighbor_list_excessive)
999 :
1000 384 : ALLOCATE (almo_scf_env%domain_map(ispin)%index1(ndomains))
1001 384 : ALLOCATE (almo_scf_env%domain_map(ispin)%pairs(max_domain_neighbors*ndomains, 2))
1002 12956 : almo_scf_env%domain_map(ispin)%pairs(:, :) = 0
1003 962 : almo_scf_env%domain_map(ispin)%index1(:) = 0
1004 128 : domain_map_local_entries = 0
1005 :
1006 : ! RZK-warning intermediate [0,1] quencher values are ill-defined
1007 : ! for molecules (not continuous and conceptually inadequate)
1008 :
1009 : CALL dbcsr_get_info(almo_scf_env%quench_t(ispin), &
1010 128 : row_blk_size=row_blk_size, col_blk_size=col_blk_size)
1011 : ! O(N) loop over domain pairs
1012 962 : DO row = 1, nblkrows_tot
1013 7240 : DO col = 1, current_number_neighbors(row)
1014 6278 : tr = .FALSE.
1015 6278 : iblock_row = row
1016 6278 : iblock_col = domain_neighbor_list(row, col)
1017 : CALL dbcsr_get_stored_coordinates(almo_scf_env%quench_t(ispin), &
1018 6278 : iblock_row, iblock_col, hold)
1019 :
1020 7112 : IF (hold == mynode) THEN
1021 :
1022 : ! Translate indices of distribution blocks to indices of domain blocks
1023 : ! Rows are AOs
1024 3139 : domain_row = almo_scf_env%domain_index_of_ao_block(iblock_row)
1025 : ! Columns are electrons (i.e. MOs)
1026 3139 : domain_col = almo_scf_env%domain_index_of_mo_block(iblock_col)
1027 :
1028 3139 : SELECT CASE (almo_scf_env%constraint_type)
1029 : CASE (almo_constraint_block_diagonal)
1030 :
1031 0 : block_active = .FALSE.
1032 : ! type of electron groups
1033 0 : IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular) THEN
1034 :
1035 : ! type of ao domains
1036 0 : IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
1037 :
1038 : ! ao domains are molecular / electron groups are molecular
1039 0 : IF (domain_row == domain_col) THEN
1040 : block_active = .TRUE.
1041 : END IF
1042 :
1043 : ELSE ! ao domains are atomic
1044 :
1045 : ! ao domains are atomic / electron groups are molecular
1046 0 : CPABORT("Illegal: atomic domains and molecular groups")
1047 :
1048 : END IF
1049 :
1050 : ELSE ! electron groups are atomic
1051 :
1052 : ! type of ao domains
1053 0 : IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
1054 :
1055 : ! ao domains are molecular / electron groups are atomic
1056 0 : CPABORT("Illegal: molecular domains and atomic groups")
1057 :
1058 : ELSE
1059 :
1060 : ! ao domains are atomic / electron groups are atomic
1061 0 : IF (domain_row == domain_col) THEN
1062 : block_active = .TRUE.
1063 : END IF
1064 :
1065 : END IF
1066 :
1067 : END IF ! end type of electron groups
1068 :
1069 0 : IF (block_active) THEN
1070 :
1071 0 : ALLOCATE (new_block(row_blk_size(iblock_row), col_blk_size(iblock_col)))
1072 0 : new_block(:, :) = 1.0_dp
1073 0 : CALL dbcsr_put_block(almo_scf_env%quench_t(ispin), iblock_row, iblock_col, new_block)
1074 0 : DEALLOCATE (new_block)
1075 :
1076 0 : IF (domain_map_local_entries >= max_domain_neighbors*almo_scf_env%ndomains) THEN
1077 0 : CPABORT("weird... max_domain_neighbors is exceeded")
1078 : END IF
1079 0 : almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 1) = iblock_row
1080 0 : almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 2) = iblock_col
1081 0 : domain_map_local_entries = domain_map_local_entries + 1
1082 :
1083 : END IF
1084 :
1085 : CASE (almo_constraint_ao_overlap)
1086 :
1087 : ! type of electron groups
1088 0 : IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular) THEN
1089 :
1090 : ! type of ao domains
1091 0 : IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
1092 :
1093 : ! ao domains are molecular / electron groups are molecular
1094 :
1095 : ! compute the maximum overlap between the atoms of the two molecules
1096 0 : CALL dbcsr_get_block_p(matrix_s_sym, iblock_row, iblock_col, p_old_block, found)
1097 0 : IF (found) THEN
1098 0 : overlap = MAXVAL(ABS(p_old_block))
1099 : ELSE
1100 : overlap = 0.0_dp
1101 : END IF
1102 :
1103 : ELSE ! ao domains are atomic
1104 :
1105 : ! ao domains are atomic / electron groups are molecular
1106 : ! overlap_between_atom_and_molecule(atom=domain_row,molecule=domain_col)
1107 0 : CPABORT("atomic domains and molecular groups - NYI")
1108 :
1109 : END IF
1110 :
1111 : ELSE ! electron groups are atomic
1112 :
1113 : ! type of ao domains
1114 0 : IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
1115 :
1116 : ! ao domains are molecular / electron groups are atomic
1117 : ! overlap_between_atom_and_molecule(atom=domain_col,molecule=domain_row)
1118 0 : CPABORT("molecular domains and atomic groups - NYI")
1119 :
1120 : ELSE
1121 :
1122 : ! ao domains are atomic / electron groups are atomic
1123 : ! compute max overlap between atoms: domain_row and domain_col
1124 0 : CALL dbcsr_get_block_p(matrix_s_sym, iblock_row, iblock_col, p_old_block, found)
1125 0 : IF (found) THEN
1126 0 : overlap = MAXVAL(ABS(p_old_block))
1127 : ELSE
1128 : overlap = 0.0_dp
1129 : END IF
1130 :
1131 : END IF
1132 :
1133 : END IF ! end type of electron groups
1134 :
1135 0 : s0 = -LOG10(ABS(almo_scf_env%quencher_s0))
1136 0 : s1 = -LOG10(ABS(almo_scf_env%quencher_s1))
1137 0 : IF (overlap == 0.0_dp) THEN
1138 0 : overlap = -LOG10(ABS(almo_scf_env%eps_filter)) + 100.0_dp
1139 : ELSE
1140 0 : overlap = -LOG10(overlap)
1141 : END IF
1142 0 : IF (s0 < 0.0_dp) THEN
1143 0 : CPABORT("S0 is less than zero")
1144 : END IF
1145 0 : IF (s1 <= 0.0_dp) THEN
1146 0 : CPABORT("S1 is less than or equal to zero")
1147 : END IF
1148 0 : IF (s0 >= s1) THEN
1149 0 : CPABORT("S0 is greater than or equal to S1")
1150 : END IF
1151 :
1152 : ! Fill in non-zero blocks if AOs are close to the electron center
1153 0 : IF (overlap < s1) THEN
1154 0 : ALLOCATE (new_block(row_blk_size(iblock_row), col_blk_size(iblock_col)))
1155 0 : IF (overlap <= s0) THEN
1156 0 : new_block(:, :) = 1.0_dp
1157 : ELSE
1158 0 : new_block(:, :) = 1.0_dp/(1.0_dp + EXP(-(s0 - s1)/(s0 - overlap) - (s0 - s1)/(overlap - s1)))
1159 : END IF
1160 :
1161 0 : IF (ABS(new_block(1, 1)) > ABS(almo_scf_env%eps_filter)) THEN
1162 0 : IF (domain_map_local_entries >= max_domain_neighbors*almo_scf_env%ndomains) THEN
1163 0 : CPABORT("weird... max_domain_neighbors is exceeded")
1164 : END IF
1165 0 : almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 1) = iblock_row
1166 0 : almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 2) = iblock_col
1167 0 : domain_map_local_entries = domain_map_local_entries + 1
1168 : END IF
1169 :
1170 0 : CALL dbcsr_put_block(almo_scf_env%quench_t(ispin), iblock_row, iblock_col, new_block)
1171 0 : DEALLOCATE (new_block)
1172 :
1173 : END IF
1174 :
1175 : CASE (almo_constraint_distance)
1176 :
1177 : ! type of electron groups
1178 3139 : IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular) THEN
1179 :
1180 : ! type of ao domains
1181 3139 : IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
1182 :
1183 : ! ao domains are molecular / electron groups are molecular
1184 :
1185 : ! compute distance between molecules: domain_row and domain_col
1186 : ! distance between molecules is defined as the smallest
1187 : ! distance among all atom pairs
1188 3139 : IF (domain_row == domain_col) THEN
1189 417 : distance = 0.0_dp
1190 417 : contact_atom_1 = first_atom_of_molecule(domain_row)
1191 417 : contact_atom_2 = first_atom_of_molecule(domain_col)
1192 : ELSE
1193 2722 : distance_squared = 1.0E+100_dp
1194 2722 : contact_atom_1 = -1
1195 2722 : contact_atom_2 = -1
1196 9074 : DO iatom = first_atom_of_molecule(domain_row), last_atom_of_molecule(domain_row)
1197 26414 : DO jatom = first_atom_of_molecule(domain_col), last_atom_of_molecule(domain_col)
1198 17340 : rab(:) = pbc(particle_set(iatom)%r(:), particle_set(jatom)%r(:), cell)
1199 17340 : trial_distance_squared = rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3)
1200 23692 : IF (trial_distance_squared < distance_squared) THEN
1201 6391 : distance_squared = trial_distance_squared
1202 6391 : contact_atom_1 = iatom
1203 6391 : contact_atom_2 = jatom
1204 : END IF
1205 : END DO ! jatom
1206 : END DO ! iatom
1207 2722 : CPASSERT(contact_atom_1 > 0)
1208 2722 : distance = SQRT(distance_squared)
1209 : END IF
1210 :
1211 : ELSE ! ao domains are atomic
1212 :
1213 : ! ao domains are atomic / electron groups are molecular
1214 : !distance_between_atom_and_molecule(atom=domain_row,molecule=domain_col)
1215 0 : CPABORT("atomic domains and molecular groups - NYI")
1216 :
1217 : END IF
1218 :
1219 : ELSE ! electron groups are atomic
1220 :
1221 : ! type of ao domains
1222 0 : IF (almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
1223 :
1224 : ! ao domains are molecular / electron groups are atomic
1225 : !distance_between_atom_and_molecule(atom=domain_col,molecule=domain_row)
1226 0 : CPABORT("molecular domains and atomic groups - NYI")
1227 :
1228 : ELSE
1229 :
1230 : ! ao domains are atomic / electron groups are atomic
1231 : ! compute distance between atoms: domain_row and domain_col
1232 0 : rab(:) = pbc(particle_set(domain_row)%r(:), particle_set(domain_col)%r(:), cell)
1233 0 : distance = SQRT(rab(1)*rab(1) + rab(2)*rab(2) + rab(3)*rab(3))
1234 0 : contact_atom_1 = domain_row
1235 0 : contact_atom_2 = domain_col
1236 :
1237 : END IF
1238 :
1239 : END IF ! end type of electron groups
1240 :
1241 : ! get atomic radii to compute distance cutoff threshold
1242 3139 : IF (almo_scf_env%quencher_radius_type == do_bondparm_covalent) THEN
1243 : CALL get_atomic_kind(atomic_kind=particle_set(contact_atom_1)%atomic_kind, &
1244 0 : rcov=contact1_radius)
1245 : CALL get_atomic_kind(atomic_kind=particle_set(contact_atom_2)%atomic_kind, &
1246 0 : rcov=contact2_radius)
1247 3139 : ELSE IF (almo_scf_env%quencher_radius_type == do_bondparm_vdw) THEN
1248 : CALL get_atomic_kind(atomic_kind=particle_set(contact_atom_1)%atomic_kind, &
1249 3139 : rvdw=contact1_radius)
1250 : CALL get_atomic_kind(atomic_kind=particle_set(contact_atom_2)%atomic_kind, &
1251 3139 : rvdw=contact2_radius)
1252 : ELSE
1253 0 : CPABORT("Illegal quencher_radius_type")
1254 : END IF
1255 3139 : contact1_radius = cp_unit_to_cp2k(contact1_radius, "angstrom")
1256 3139 : contact2_radius = cp_unit_to_cp2k(contact2_radius, "angstrom")
1257 :
1258 : !RZK-warning the procedure is faulty for molecules:
1259 : ! the closest contacts should be found using
1260 : ! the element specific radii
1261 :
1262 : ! compute inner and outer cutoff radii
1263 3139 : r0 = almo_scf_env%quencher_r0_factor*(contact1_radius + contact2_radius)
1264 : !+almo_scf_env%quencher_r0_shift
1265 3139 : r1 = almo_scf_env%quencher_r1_factor*(contact1_radius + contact2_radius)
1266 : !+almo_scf_env%quencher_r1_shift
1267 :
1268 3139 : IF (r0 < 0.0_dp) THEN
1269 0 : CPABORT("R0 is less than zero")
1270 : END IF
1271 3139 : IF (r1 <= 0.0_dp) THEN
1272 0 : CPABORT("R1 is less than or equal to zero")
1273 : END IF
1274 3139 : IF (r0 > r1) THEN
1275 0 : CPABORT("R0 is greater than or equal to R1")
1276 : END IF
1277 :
1278 : ! Fill in non-zero blocks if AOs are close to the electron center
1279 3139 : IF (distance < r1) THEN
1280 8740 : ALLOCATE (new_block(row_blk_size(iblock_row), col_blk_size(iblock_col)))
1281 2185 : IF (distance <= r0) THEN
1282 101919 : new_block(:, :) = 1.0_dp
1283 : ELSE
1284 : ! remove the intermediate values from the quencher temporarily
1285 0 : CPABORT("distance > r0 not yet validated") ! Unexplained in https://github.com/cp2k/cp2k/pull/5345
1286 0 : new_block(:, :) = 1.0_dp/(1.0_dp + EXP((r1 - r0)/(r0 - distance) + (r1 - r0)/(r1 - distance)))
1287 : END IF
1288 :
1289 2185 : IF (ABS(new_block(1, 1)) > ABS(almo_scf_env%eps_filter)) THEN
1290 2185 : IF (domain_map_local_entries >= max_domain_neighbors*almo_scf_env%ndomains) THEN
1291 0 : CPABORT("weird... max_domain_neighbors is exceeded")
1292 : END IF
1293 2185 : almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 1) = iblock_row
1294 2185 : almo_scf_env%domain_map(ispin)%pairs(domain_map_local_entries + 1, 2) = iblock_col
1295 2185 : domain_map_local_entries = domain_map_local_entries + 1
1296 : END IF
1297 :
1298 2185 : CALL dbcsr_put_block(almo_scf_env%quench_t(ispin), iblock_row, iblock_col, new_block)
1299 2185 : DEALLOCATE (new_block)
1300 : END IF
1301 :
1302 : CASE DEFAULT
1303 3139 : CPABORT("Illegal constraint type")
1304 : END SELECT
1305 :
1306 : END IF ! mynode
1307 :
1308 : END DO
1309 : END DO ! end O(N) loop over pairs
1310 :
1311 128 : DEALLOCATE (domain_neighbor_list)
1312 128 : DEALLOCATE (current_number_neighbors)
1313 :
1314 128 : CALL dbcsr_finalize(almo_scf_env%quench_t(ispin))
1315 :
1316 : CALL dbcsr_filter(almo_scf_env%quench_t(ispin), &
1317 128 : almo_scf_env%eps_filter)
1318 :
1319 : ! check that both domain_map and quench_t have the same number of entries
1320 128 : nblks = dbcsr_get_num_blocks(almo_scf_env%quench_t(ispin))
1321 128 : IF (nblks /= domain_map_local_entries) THEN
1322 0 : CPABORT("number of blocks is wrong")
1323 : END IF
1324 :
1325 : ! first, communicate map sizes on the other nodes
1326 384 : ALLOCATE (domain_entries_cpu(nNodes), offset_for_cpu(nNodes))
1327 128 : CALL group%allgather(2*domain_map_local_entries, domain_entries_cpu)
1328 :
1329 : ! second, create
1330 128 : offset_for_cpu(1) = 0
1331 256 : DO iNode = 2, nNodes
1332 : offset_for_cpu(iNode) = offset_for_cpu(iNode - 1) + &
1333 256 : domain_entries_cpu(iNode - 1)
1334 : END DO
1335 128 : global_entries = offset_for_cpu(nNodes) + domain_entries_cpu(nNodes)
1336 :
1337 : ! communicate all entries
1338 384 : ALLOCATE (domain_map_global(global_entries))
1339 508 : ALLOCATE (domain_map_local(2*domain_map_local_entries))
1340 2313 : DO ientry = 1, domain_map_local_entries
1341 2185 : domain_map_local(2*(ientry - 1) + 1) = almo_scf_env%domain_map(ispin)%pairs(ientry, 1)
1342 2313 : domain_map_local(2*ientry) = almo_scf_env%domain_map(ispin)%pairs(ientry, 2)
1343 : END DO
1344 : CALL group%allgatherv(domain_map_local, domain_map_global, &
1345 128 : domain_entries_cpu, offset_for_cpu)
1346 128 : DEALLOCATE (domain_entries_cpu, offset_for_cpu)
1347 128 : DEALLOCATE (domain_map_local)
1348 :
1349 128 : DEALLOCATE (almo_scf_env%domain_map(ispin)%index1)
1350 128 : DEALLOCATE (almo_scf_env%domain_map(ispin)%pairs)
1351 256 : ALLOCATE (almo_scf_env%domain_map(ispin)%index1(ndomains))
1352 512 : ALLOCATE (almo_scf_env%domain_map(ispin)%pairs(global_entries/2, 2))
1353 9124 : almo_scf_env%domain_map(ispin)%pairs(:, :) = 0
1354 962 : almo_scf_env%domain_map(ispin)%index1(:) = 0
1355 :
1356 : ! unpack the received data into a local variable
1357 : ! since we do not know the maximum global number of neighbors
1358 : ! try one. if fails increase the maximum number and try again
1359 : ! until it succeeds
1360 : max_neig = max_domain_neighbors
1361 : max_neig_fails = .TRUE.
1362 256 : max_neig_loop: DO WHILE (max_neig_fails)
1363 512 : ALLOCATE (domain_grid(almo_scf_env%ndomains, 0:max_neig))
1364 128 : domain_grid(:, :) = 0
1365 : ! init the number of collected neighbors
1366 962 : domain_grid(:, 0) = 1
1367 : ! loop over the records
1368 128 : global_entries = global_entries/2
1369 4498 : DO ientry = 1, global_entries
1370 : ! get the center
1371 4370 : grid1 = domain_map_global(2*ientry)
1372 : ! get the neighbor
1373 4370 : ineig = domain_map_global(2*(ientry - 1) + 1)
1374 : ! check boundaries
1375 4370 : IF (domain_grid(grid1, 0) > max_neig) THEN
1376 : ! this neighbor will overstep the boundaries
1377 : ! stop the trial and increase the max number of neighbors
1378 0 : DEALLOCATE (domain_grid)
1379 0 : max_neig = max_neig*2
1380 0 : CYCLE max_neig_loop
1381 : END IF
1382 : ! for the current center loop over the collected neighbors
1383 : ! to insert the current record in a numerical order
1384 : delayed_increment = .FALSE.
1385 19016 : DO igrid = 1, domain_grid(grid1, 0)
1386 : ! compare the current neighbor with that already in the 'book'
1387 19016 : IF (ineig < domain_grid(grid1, igrid)) THEN
1388 : ! if this one is smaller then insert it here and pick up the one
1389 : ! from the book to continue inserting
1390 3180 : neig_temp = ineig
1391 3180 : ineig = domain_grid(grid1, igrid)
1392 3180 : domain_grid(grid1, igrid) = neig_temp
1393 : ELSE
1394 11466 : IF (domain_grid(grid1, igrid) == 0) THEN
1395 : ! got the empty slot now - insert the record
1396 4370 : domain_grid(grid1, igrid) = ineig
1397 : ! increase the record counter but do it outside the loop
1398 4370 : delayed_increment = .TRUE.
1399 : END IF
1400 : END IF
1401 : END DO
1402 4498 : IF (delayed_increment) THEN
1403 4370 : domain_grid(grid1, 0) = domain_grid(grid1, 0) + 1
1404 : ELSE
1405 : ! should not be here - all records must be inserted
1406 0 : CPABORT("all records must be inserted")
1407 : END IF
1408 : END DO
1409 128 : max_neig_fails = .FALSE.
1410 : END DO max_neig_loop
1411 128 : DEALLOCATE (domain_map_global)
1412 :
1413 128 : ientry = 1
1414 962 : DO idomain = 1, almo_scf_env%ndomains
1415 5204 : DO ineig = 1, domain_grid(idomain, 0) - 1
1416 4370 : almo_scf_env%domain_map(ispin)%pairs(ientry, 1) = domain_grid(idomain, ineig)
1417 4370 : almo_scf_env%domain_map(ispin)%pairs(ientry, 2) = idomain
1418 5204 : ientry = ientry + 1
1419 : END DO
1420 962 : almo_scf_env%domain_map(ispin)%index1(idomain) = ientry
1421 : END DO
1422 378 : DEALLOCATE (domain_grid)
1423 :
1424 : END DO ! ispin
1425 122 : IF (almo_scf_env%nspins == 2) THEN
1426 : CALL dbcsr_copy(almo_scf_env%quench_t(2), &
1427 6 : almo_scf_env%quench_t(1))
1428 : almo_scf_env%domain_map(2)%pairs(:, :) = &
1429 50 : almo_scf_env%domain_map(1)%pairs(:, :)
1430 : almo_scf_env%domain_map(2)%index1(:) = &
1431 18 : almo_scf_env%domain_map(1)%index1(:)
1432 : END IF
1433 :
1434 122 : CALL dbcsr_release(matrix_s_sym)
1435 :
1436 122 : IF (almo_scf_env%domain_layout_mos == almo_domain_layout_molecular .OR. &
1437 : almo_scf_env%domain_layout_aos == almo_domain_layout_molecular) THEN
1438 122 : DEALLOCATE (first_atom_of_molecule)
1439 122 : DEALLOCATE (last_atom_of_molecule)
1440 : END IF
1441 :
1442 122 : CALL timestop(handle)
1443 :
1444 244 : END SUBROUTINE almo_scf_construct_quencher
1445 :
1446 : ! *****************************************************************************
1447 : !> \brief Compute matrix W (energy-weighted density matrix) that is needed
1448 : !> for the evaluation of forces
1449 : !> \param matrix_w ...
1450 : !> \param almo_scf_env ...
1451 : !> \par History
1452 : !> 2015.03 created [Rustam Z. Khaliullin]
1453 : !> \author Rustam Z. Khaliullin
1454 : ! **************************************************************************************************
1455 66 : SUBROUTINE calculate_w_matrix_almo(matrix_w, almo_scf_env)
1456 : TYPE(dbcsr_p_type), DIMENSION(:), POINTER :: matrix_w
1457 : TYPE(almo_scf_env_type) :: almo_scf_env
1458 :
1459 : CHARACTER(len=*), PARAMETER :: routineN = 'calculate_w_matrix_almo'
1460 :
1461 : INTEGER :: handle, ispin
1462 : REAL(KIND=dp) :: scaling
1463 : TYPE(dbcsr_type) :: tmp_nn1, tmp_no1, tmp_oo1, tmp_oo2
1464 :
1465 66 : CALL timeset(routineN, handle)
1466 :
1467 66 : IF (almo_scf_env%nspins == 1) THEN
1468 66 : scaling = 2.0_dp
1469 : ELSE
1470 0 : scaling = 1.0_dp
1471 : END IF
1472 :
1473 132 : DO ispin = 1, almo_scf_env%nspins
1474 :
1475 : CALL dbcsr_create(tmp_nn1, template=almo_scf_env%matrix_s(1), &
1476 66 : matrix_type=dbcsr_type_no_symmetry)
1477 : CALL dbcsr_create(tmp_no1, template=almo_scf_env%matrix_t(ispin), &
1478 66 : matrix_type=dbcsr_type_no_symmetry)
1479 : CALL dbcsr_create(tmp_oo1, template=almo_scf_env%matrix_sigma_inv(ispin), &
1480 66 : matrix_type=dbcsr_type_no_symmetry)
1481 : CALL dbcsr_create(tmp_oo2, template=almo_scf_env%matrix_sigma_inv(ispin), &
1482 66 : matrix_type=dbcsr_type_no_symmetry)
1483 :
1484 66 : CALL dbcsr_copy(tmp_nn1, almo_scf_env%matrix_ks(ispin))
1485 : ! 1. TMP_NO1=F.T
1486 : CALL dbcsr_multiply("N", "N", scaling, tmp_nn1, almo_scf_env%matrix_t(ispin), &
1487 66 : 0.0_dp, tmp_no1, filter_eps=almo_scf_env%eps_filter)
1488 : ! 2. TMP_OO1=T^(tr).TMP_NO1=T^(tr).(FT)
1489 : CALL dbcsr_multiply("T", "N", 1.0_dp, almo_scf_env%matrix_t(ispin), tmp_no1, &
1490 66 : 0.0_dp, tmp_oo1, filter_eps=almo_scf_env%eps_filter)
1491 : ! 3. TMP_OO2=TMP_OO1.siginv=(T^(tr)FT).siginv
1492 : CALL dbcsr_multiply("N", "N", 1.0_dp, tmp_oo1, almo_scf_env%matrix_sigma_inv(ispin), &
1493 66 : 0.0_dp, tmp_oo2, filter_eps=almo_scf_env%eps_filter)
1494 : ! 4. TMP_OO1=siginv.TMP_OO2=siginv.(T^(tr)FTsiginv)
1495 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_sigma_inv(ispin), tmp_oo2, &
1496 66 : 0.0_dp, tmp_oo1, filter_eps=almo_scf_env%eps_filter)
1497 : ! 5. TMP_NO1=T.TMP_OO1.=T.(siginvT^(tr)FTsiginv)
1498 : CALL dbcsr_multiply("N", "N", 1.0_dp, almo_scf_env%matrix_t(ispin), tmp_oo1, &
1499 66 : 0.0_dp, tmp_no1, filter_eps=almo_scf_env%eps_filter)
1500 : ! 6. TMP_NN1=TMP_NO1.T^(tr)=(TsiginvT^(tr)FTsiginv).T^(tr)=RFR
1501 : CALL dbcsr_multiply("N", "T", 1.0_dp, tmp_no1, almo_scf_env%matrix_t(ispin), &
1502 66 : 0.0_dp, tmp_nn1, filter_eps=almo_scf_env%eps_filter)
1503 66 : CALL matrix_almo_to_qs(tmp_nn1, matrix_w(ispin)%matrix, almo_scf_env%mat_distr_aos)
1504 :
1505 66 : CALL dbcsr_release(tmp_nn1)
1506 66 : CALL dbcsr_release(tmp_no1)
1507 66 : CALL dbcsr_release(tmp_oo1)
1508 132 : CALL dbcsr_release(tmp_oo2)
1509 :
1510 : END DO
1511 :
1512 66 : CALL timestop(handle)
1513 :
1514 66 : END SUBROUTINE calculate_w_matrix_almo
1515 :
1516 : END MODULE almo_scf_qs
1517 :
|