(git:f2099e5)
Loading...
Searching...
No Matches
gw_ri_rs_compute_Z_lP.F
Go to the documentation of this file.
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 Computes the RI-RS fitting matrix Z_lP.
10!> \par History
11!> 09.2026 created Jan Wilhelm
12!> 09.2026 moved code by Ritaj Tyagi from gw_ri_rs_non_periodic.F
13!> 09.2026 added routine to compute Z_lP for automatic RI optimization
14! **************************************************************************************************
19 USE cell_types, ONLY: cell_type,&
20 pbc
24 USE cp_dbcsr_api, ONLY: &
28 dbcsr_release, dbcsr_set, dbcsr_type, dbcsr_type_no_symmetry
31 USE cp_fm_types, ONLY: cp_fm_type
34 USE cp_output_handling, ONLY: cp_p_file,&
51 USE kinds, ONLY: dp
52 USE libint_2c_3c, ONLY: eri_3center
53 USE machine, ONLY: m_flush,&
57 USE orbital_pointers, ONLY: ncoset
59 USE physcon, ONLY: angstrom
64 USE util, ONLY: sort
65#include "./base/base_uses.f90"
66
67 IMPLICIT NONE
68 PRIVATE
69
70 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'gw_ri_rs_compute_Z_lP'
71
72 PUBLIC :: compute_z_lp
73
74CONTAINS
75
76! **************************************************************************************************
77!> \brief Computes Z_lP for (1) a tabulated RI basis set or (2) an on-the-fly generated RI basis set.
78!>
79!> In both cases, the Z_lP coefficients are computed by solving the linear system
80!>
81!> Σ_l' D_ll' Z_l'P = d_lP,
82!>
83!> with D_ll' and d_lP given by
84!>
85!> D_ll' = [Σ_μ ϕ_μ(r_l) ϕ_μ(r_l')]²,
86!>
87!> d_lP = Σ_μν ϕ_μ(r_l) ϕ_ν(r_l) (μν|P).
88!>
89!> For an on-the-fly generated RI basis set, an RI function φ_P may be a contraction of
90!> Gaussians on neighboring atoms, which requires special computation of d_lP.
91!>
92!> \param qs_env ...
93!> \param bs_env Band-structure environment containing GW parameters.
94!> \param ri_rs_grid_points ...
95!> \param mat_phi_mu_l ...
96!> \param mat_Z_lP ...
97! **************************************************************************************************
98 SUBROUTINE compute_z_lp(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_Z_lP)
99 TYPE(qs_environment_type), POINTER :: qs_env
100 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
101 REAL(kind=dp), ALLOCATABLE, INTENT(INOUT) :: ri_rs_grid_points(:, :)
102 TYPE(dbcsr_type), INTENT(INOUT) :: mat_phi_mu_l
103 TYPE(dbcsr_type), INTENT(OUT) :: mat_z_lp
104
105 CHARACTER(LEN=*), PARAMETER :: routinen = 'compute_Z_lP'
106
107 INTEGER :: handle
108
109 CALL timeset(routinen, handle)
110
111 IF (bs_env%auto_ri%enabled) THEN
112 CALL compute_z_lp_auto_ri(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_z_lp)
113 ELSE
114 CALL compute_z_lp_standard(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_z_lp)
115 END IF
116
117 CALL timestop(handle)
118
119 END SUBROUTINE compute_z_lp
120
121! **************************************************************************************************
122!> \brief Computes the RI-RS fitting coefficients Z_lP by solving, independently for every RI
123!> atom P, a Jacobi-conditioned, Tikhonov-regularized linear system restricted to the
124!> grid points r_l inside P's integration sphere |r_l - R_P| <= cutoff_ri(P):
125!>
126!> 1. D_ll' = [ Σ_μ ϕ_μ(r_l) ϕ_μ(r_l') ]²
127!> 2. d_l = 1 / sqrt(D_ll) (Jacobi conditioning vector)
128!> 3. D'_ll' = d_l D_ll' d_l' + λ δ_ll' (λ = TIKHONOV regularization)
129!> 4. d_lP = Σ_μν ϕ_μ(r_l) ϕ_ν(r_l) (μν|P)
130!> 5. Σ_l' D'_ll' Z'_l'P = d_l d_lP (solve linear system for Z'_lP)
131!> 6. Z_lP = d_l Z'_l'P (undo the conditioning)
132!>
133!> Work is distributed over atoms in two phases (planned by classify_z_lp_atoms and
134!> lpt_assign_atoms): Phase A solves "small" atoms with single-rank LAPACK
135!> (dpotrf/dpotrs); Phase B solves "big" atoms, whose dense matrix D'_ll' would exceed one
136!> rank's memory, with ScaLAPACK (pdpotrf/pdpotrs) over rank subgroups of size G.
137!> The solved Z columns are scattered into the sparse global mat_Z_lP.
138!> If a Z_lP restart file exists, it is read instead and the solve is skipped entirely.
139!> \param qs_env ...
140!> \param bs_env ...
141!> \param ri_rs_grid_points ...
142!> \param mat_phi_mu_l ...
143!> \param mat_Z_lP ...
144! **************************************************************************************************
145 SUBROUTINE compute_z_lp_standard(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_Z_lP)
146
147 TYPE(qs_environment_type), POINTER :: qs_env
148 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
149 REAL(kind=dp), ALLOCATABLE, INTENT(INOUT) :: ri_rs_grid_points(:, :)
150 TYPE(dbcsr_type), INTENT(INOUT) :: mat_phi_mu_l
151 TYPE(dbcsr_type), INTENT(OUT) :: mat_z_lp
152
153 CHARACTER(LEN=*), PARAMETER :: key = 'PROPERTIES%BANDSTRUCTURE%GW%PRINT%RESTART', &
154 routinen = 'compute_Z_lP_standard'
155
156 INTEGER :: atom_j_mepos, atom_j_stride, atom_p, g, handle, handle_dpotrf, handle_dpotrs, &
157 i_blk, iatom, idx, info, iphase, j, max_ao_size, my_group, n_ao_total, n_ao_used, n_big, &
158 n_done, n_groups, n_loc_ri, n_local_grid, n_my_atoms, n_small, natom, npcol_phi, &
159 num_grid_chunks, phase_hi
160 INTEGER, ALLOCATABLE, DIMENSION(:) :: ao_col_map, big_list, local_grid_idx, &
161 my_atoms_a, my_atoms_b, &
162 n_local_grid_atom, row_offset, &
163 small_list
164 INTEGER, DIMENSION(:), POINTER :: col_dist_ri, r_blk_sizes, ri_blk_sizes, &
165 row_dist_grid
166 LOGICAL :: do_scatter, use_dist
167 REAL(kind=dp) :: balance_a, balance_b, cutoff_ri, &
168 item_start_time, r_c, t1
169 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: cutoff_ri_per_atom, d_vec_local
170 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: d_local, d_lp_local, phi_local
171 TYPE(cell_type), POINTER :: cell
172 TYPE(cp_blacs_env_type), POINTER :: blacs_env_sub
173 TYPE(cp_fm_struct_type), POINTER :: fm_struct_b, fm_struct_d
174 TYPE(cp_fm_type) :: fm_b, fm_d
175 TYPE(cp_logger_type), POINTER :: logger
176 TYPE(dbcsr_distribution_type) :: dist_phi, dist_z
177 TYPE(gw_3c_ctx_type) :: ctx_3c
178 TYPE(mp_para_env_type), POINTER :: para_env, para_env_sub
179 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
180 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
181 TYPE(section_vals_type), POINTER :: input
182
183 CALL timeset(routinen, handle)
184
185 t1 = m_walltime()
186
187 CALL get_qs_env(qs_env, para_env=para_env, particle_set=particle_set, input=input, &
188 qs_kind_set=qs_kind_set, cell=cell)
189
190 NULLIFY (para_env_sub, blacs_env_sub)
191
192 natom = bs_env%n_atom
193 n_ao_total = bs_env%i_ao_end_from_atom(natom)
194
195 ! =========================================================================
196 ! 1. SETUP DBCSR TOPOLOGY & EXACT OFFSETS
197 ! mat_Z_lP inherits the grid row blocking (and row distribution) of
198 ! mat_phi_mu_l; its columns are one block per RI atom.
199 ! =========================================================================
200 CALL dbcsr_get_info(mat_phi_mu_l, row_blk_size=r_blk_sizes, distribution=dist_phi)
201 CALL dbcsr_distribution_get(dist_phi, row_dist=row_dist_grid, npcols=npcol_phi)
202
203 num_grid_chunks = SIZE(r_blk_sizes)
204
205 ALLOCATE (row_offset(num_grid_chunks))
206 row_offset(1) = 0
207 DO i_blk = 2, num_grid_chunks
208 row_offset(i_blk) = row_offset(i_blk - 1) + r_blk_sizes(i_blk - 1)
209 END DO
210
211 ALLOCATE (ri_blk_sizes(natom), col_dist_ri(natom))
212 DO iatom = 1, natom
213 ri_blk_sizes(iatom) = &
214 bs_env%i_RI_end_from_atom(iatom) - bs_env%i_RI_start_from_atom(iatom) + 1
215 col_dist_ri(iatom) = mod(iatom - 1, npcol_phi)
216 END DO
217
218 CALL dbcsr_distribution_new(dist_z, template=dist_phi, &
219 row_dist=row_dist_grid, col_dist=col_dist_ri)
220
221 IF (bs_env%ri_rs%Z_lP_exists) THEN
222 CALL dbcsr_binary_read(filepath=trim(bs_env%prefix)//"Z_lP.matrix", &
223 distribution=dist_z, &
224 matrix_new=mat_z_lp)
225 IF (bs_env%unit_nr > 0) THEN
226 WRITE (bs_env%unit_nr, '(T2,A,T57,A,F7.1,A)') &
227 'Read Z_lP from file ', ' Execution time', m_walltime() - t1, ' s'
228 ! The grid rows use Morton order (spatial_atom_order). A Z_lP.matrix
229 ! written with another grid ordering would be silently read into
230 ! the current row order. Delete stale Z_lP.matrix files and recompute if in doubt.
231 WRITE (bs_env%unit_nr, '(T2,A)') &
232 '*** NOTE: Z_lP restart must match the current (spatial) grid row ordering ***'
233 WRITE (bs_env%unit_nr, '(A)') ' '
234 END IF
235 ELSE
236
237 IF (bs_env%unit_nr > 0) THEN
238 WRITE (bs_env%unit_nr, '(A)') ' '
239 WRITE (bs_env%unit_nr, '(T2,A)') 'Started computing Z_lP'
240 CALL m_flush(bs_env%unit_nr)
241 END IF
242 CALL dbcsr_create(mat_z_lp, name="mat_Z_lP", dist=dist_z, &
243 matrix_type=dbcsr_type_no_symmetry, &
244 row_blk_size=r_blk_sizes, col_blk_size=ri_blk_sizes)
245
246 ! Largest per-atom AO block, needed to size the 3c-integral work buffers.
247 max_ao_size = 0
248 DO j = 1, bs_env%n_atom
249 max_ao_size = max(max_ao_size, &
250 bs_env%i_ao_end_from_atom(j) - &
251 bs_env%i_ao_start_from_atom(j) + 1)
252 END DO
253
254 ! Per-atom RI-RS integration sphere:
255 ! cutoff_ri(P) = r_c + r_RI(P)
256 ! where r_c is the truncated-Coulomb cutoff of the RI metric and r_RI the radius of
257 ! the most diffuse RI auxiliary Gaussian on P. The CUTOFF_RADIUS_RL_RI keyword
258 ! (when > 0) overrides the entire cutoff calculation.
259 ALLOCATE (cutoff_ri_per_atom(natom))
260
261 IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp) THEN
262 cutoff_ri_per_atom(:) = bs_env%ri_rs%cutoff_radius_ri_rs
263 ELSE
264 r_c = bs_env%ri_metric%cutoff_radius
265 DO iatom = 1, natom
266 cutoff_ri_per_atom(iatom) = r_c + bs_env%ri_rs%radius_ri_per_atom(iatom)
267 END DO
268 END IF
269
270 CALL print_sphere_cutoff_table(bs_env, cutoff_ri_per_atom)
271
272 ! =========================================================================
273 ! 2. PER-ATOM SOLVER CLASSIFICATION
274 ! Split the atoms into "small" (single-rank LAPACK, Phase A) and "big"
275 ! (distributed ScaLAPACK over subgroups of G ranks, Phase B) by comparing
276 ! each atom's estimated solve peak memory against the measured budget.
277 ! =========================================================================
278 CALL classify_z_lp_atoms(bs_env, ri_rs_grid_points, cutoff_ri_per_atom, ri_blk_sizes, &
279 n_local_grid_atom, small_list, n_small, big_list, n_big, g)
280
281 ! LPT scheduling: sort the atoms of each phase by estimated solve cost
282 ! (n_local_grid^3, Cholesky-dominated) and greedily assign to the least-loaded
283 ! rank (Phase A) / subgroup (Phase B).
284 CALL lpt_assign_atoms(small_list, n_small, n_local_grid_atom, para_env%num_pe, &
285 para_env%mepos, my_atoms_a, balance_a)
286 IF (n_big > 0) THEN
287 n_groups = para_env%num_pe/g
288 my_group = min(para_env%mepos/g, n_groups - 1)
289 CALL lpt_assign_atoms(big_list, n_big, n_local_grid_atom, n_groups, my_group, &
290 my_atoms_b, balance_b)
291 ELSE
292 ALLOCATE (my_atoms_b(0))
293 balance_b = 1.0_dp
294 END IF
295
296 ! Atoms this rank will process across both phases for rank-0 progress
297 n_my_atoms = SIZE(my_atoms_a) + SIZE(my_atoms_b)
298 n_done = 0
299
300 ! Shared context for the three-center integrals (μν|P) of the RHS build
301 CALL gw_3c_ctx_create(ctx_3c, bs_env, bs_env%ri_metric, &
302 basis_j=bs_env%basis_set_AO, basis_k=bs_env%basis_set_AO, &
303 basis_i=bs_env%basis_set_RI)
304
305 ! =========================================================================
306 ! 3. TWO-PHASE LOOP OVER ATOMS
307 ! Phase A processes the "small" atoms with the single-rank BLAS path
308 ! Phase B processes the "big" atoms with the distributed ScaLAPACK path
309 ! over rank subgroups of size G. phi_local for each atom's cutoff sphere
310 ! is built on the fly to avoid replicating a global grid x AO matrix.
311 ! =========================================================================
312 DO iphase = 1, 2
313 IF (iphase == 1) THEN
314 use_dist = .false.
315 atom_j_mepos = 0
316 atom_j_stride = 1
317 phase_hi = SIZE(my_atoms_a)
318 ELSE
319 IF (n_big == 0) cycle
320 use_dist = .true.
321 n_groups = para_env%num_pe/g
322 my_group = min(para_env%mepos/g, n_groups - 1)
323 ALLOCATE (para_env_sub)
324 CALL para_env_sub%from_split(para_env, my_group)
325 CALL cp_blacs_env_create(blacs_env=blacs_env_sub, para_env=para_env_sub)
326 atom_j_mepos = para_env_sub%mepos
327 atom_j_stride = para_env_sub%num_pe
328 ! All ranks of a subgroup share my_group, hence the identical my_atoms_B list
329 ! (the per-atom ScaLAPACK solve is collective over the subgroup).
330 phase_hi = SIZE(my_atoms_b)
331 END IF
332
333 DO idx = 1, phase_hi
334 item_start_time = m_walltime()
335 IF (iphase == 1) THEN
336 atom_p = my_atoms_a(idx)
337 ELSE
338 atom_p = my_atoms_b(idx)
339 END IF
340
341 n_loc_ri = ri_blk_sizes(atom_p)
342 cutoff_ri = cutoff_ri_per_atom(atom_p)
343
344 ! ---------------------------------------------------------------------
345 ! A. Sphere-local AO matrix ϕ_μ(r_l): select the grid points with
346 ! |r_l - R_P| <= cutoff_ri(P), evaluate every AO on them, and drop
347 ! points whose largest AO amplitude is below EPS_FILTER.
348 ! ---------------------------------------------------------------------
349 CALL build_phi_on_sphere(bs_env, qs_kind_set, &
350 ri_rs_grid_points, atom_p, cutoff_ri, n_ao_total, &
351 local_grid_idx, n_local_grid, phi_local, &
352 ao_col_map, n_ao_used)
353
354 ! ---------------------------------------------------------------------
355 ! B. Right-hand side D_lP = Σ_μν ϕ_μ(r_l) ϕ_ν(r_l) (μν|P)
356 ! ---------------------------------------------------------------------
357 ALLOCATE (d_lp_local(n_local_grid, n_loc_ri))
358 d_lp_local = 0.0_dp
359
360 CALL compute_d_lp(bs_env, ctx_3c, phi_local, ao_col_map, d_lp_local, n_local_grid, &
361 n_loc_ri, atom_p, max_ao_size, atom_j_mepos, atom_j_stride)
362
363 ! Reduce per-subgroup-rank partials into the replicated d_lp_local.
364 ! Skipped for BLAS path: each rank has the full sum locally.
365 IF (use_dist) THEN
366 CALL para_env_sub%sum(d_lp_local)
367 END IF
368
369 ! ---------------------------------------------------------------------
370 ! C. Jacobi conditioning vector d_l = 1/sqrt(D_ll) and, on the BLAS path,
371 ! the dense conditioned matrix D'_ll' = d_l D_ll' d_l' + λδ_ll'.
372 ! ---------------------------------------------------------------------
373 ALLOCATE (d_vec_local(n_local_grid))
374
375 IF (.NOT. use_dist) THEN
376 CALL build_gram_jacobi_blas(phi_local, n_local_grid, n_ao_used, &
377 bs_env%ri_rs%tikhonov, d_local, d_vec_local)
378 ELSE
379 ! ScaLAPACK path: only d_vec is needed here (= 1/||phi(r_l)||^2);
380 ! solve_D_lp_distributed builds its block-cyclic slice of D' internally
381 ! with the squared+scaled values, so no dense D_local on this rank.
382 CALL build_jacobi_diag_from_phi(phi_local, n_local_grid, n_ao_used, &
383 d_vec_local)
384 END IF
385
386 ! ---------------------------------------------------------------------
387 ! D. Pre-scale the RHS: D'_lP = d_l * D_lP
388 ! ---------------------------------------------------------------------
389 CALL scale_rows_by_diag(d_lp_local, d_vec_local, n_local_grid, n_loc_ri)
390
391 ! ---------------------------------------------------------------------
392 ! E. Cholesky solve Σ_l' D'_ll' Z'_l'P = D'_lP
393 ! (BLAS dpotrf/dpotrs or ScaLAPACK pdpotrf/pdpotrs)
394 ! ---------------------------------------------------------------------
395 IF (.NOT. use_dist) THEN
396 CALL timeset(routinen//"_dpotrf", handle_dpotrf)
397 CALL dpotrf('L', n_local_grid, d_local, n_local_grid, info)
398 CALL timestop(handle_dpotrf)
399 IF (info /= 0) cpabort("RI-RS Cholesky factorization failed")
400 CALL timeset(routinen//"_dpotrs", handle_dpotrs)
401 CALL dpotrs('L', n_local_grid, n_loc_ri, d_local, n_local_grid, &
402 d_lp_local, n_local_grid, info)
403 CALL timestop(handle_dpotrs)
404 IF (info /= 0) cpabort("RI-RS Cholesky solve failed")
405 DEALLOCATE (d_local)
406 ELSE
407 CALL solve_d_lp_distributed(phi_local, d_vec_local, d_lp_local, &
408 n_local_grid, n_ao_used, n_loc_ri, &
409 bs_env%ri_rs%tikhonov, &
410 para_env_sub, blacs_env_sub, &
411 fm_struct_d, fm_struct_b, fm_d, fm_b, info)
412 IF (info /= 0) cpabort("Distributed RI-RS Cholesky solve failed")
413 END IF
414
415 ! ---------------------------------------------------------------------
416 ! F. Undo the conditioning: Z_lP = d_l * Z'_lP
417 ! ---------------------------------------------------------------------
418 CALL scale_rows_by_diag(d_lp_local, d_vec_local, n_local_grid, n_loc_ri)
419
420 ! ---------------------------------------------------------------------
421 ! G. Scatter the solved Z columns back into the global sparse mat_Z_lP.
422 ! ---------------------------------------------------------------------
423 do_scatter = .true.
424 IF (use_dist) do_scatter = (para_env_sub%mepos == 0)
425 IF (do_scatter) THEN
426 CALL store_z_lp_columns(mat_z_lp, d_lp_local, local_grid_idx, n_local_grid, &
427 n_loc_ri, atom_p, r_blk_sizes, row_offset, &
428 bs_env%eps_filter)
429 END IF
430
431 DEALLOCATE (d_vec_local, d_lp_local)
432 DEALLOCATE (local_grid_idx, phi_local, ao_col_map)
433
434 ! Report each atom completed by the printing rank. No inter-rank communication is
435 ! needed; the final message below is printed only after the global synchronization.
436 n_done = n_done + 1
437 CALL print_z_lp_progress(bs_env, n_done, n_my_atoms, &
438 m_walltime() - item_start_time)
439 END DO ! idx: atoms of this phase owned by this rank / subgroup
440
441 ! Tear down the Phase-B subgroup (all ranks created it collectively).
442 IF (iphase == 2) THEN
443 CALL cp_blacs_env_release(blacs_env_sub)
444 CALL para_env_sub%free()
445 DEALLOCATE (para_env_sub)
446 END IF
447 END DO ! iphase
448
449 DEALLOCATE (cutoff_ri_per_atom)
450 DEALLOCATE (small_list, big_list)
451
452 CALL gw_3c_ctx_release(ctx_3c)
453
454 CALL dbcsr_finalize(mat_z_lp)
455
456 CALL para_env%sync()
457 CALL print_z_lp_progress(bs_env, natom, natom, m_walltime() - t1, &
458 all_mpi_ranks=.true.)
459
460 logger => cp_get_default_logger()
461
462 IF (btest(cp_print_key_should_output(logger%iter_info, input, key), cp_p_file)) THEN
463 CALL dbcsr_binary_write(matrix=mat_z_lp, filepath=trim(bs_env%prefix)//"Z_lP.matrix")
464 END IF
465
466 END IF
467
468 DEALLOCATE (row_offset, ri_blk_sizes, col_dist_ri)
469 CALL dbcsr_distribution_release(dist_z)
470
471 DEALLOCATE (ri_rs_grid_points)
472
473 CALL timestop(handle)
474
475 END SUBROUTINE compute_z_lp_standard
476
477! **************************************************************************************************
478!> \brief Prints the per-kind maximum RI-RS integration-sphere cutoff table.
479!> \param bs_env ...
480!> \param cutoff_ri_per_atom ...
481! **************************************************************************************************
482 SUBROUTINE print_sphere_cutoff_table(bs_env, cutoff_ri_per_atom)
483
484 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
485 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: cutoff_ri_per_atom
486
487 CHARACTER(LEN=*), PARAMETER :: routinen = 'print_sphere_cutoff_table'
488
489 INTEGER :: handle, iatom, ikind, nkind
490 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: cutoff_ri_per_kind
491 TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
492 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
493
494 CALL timeset(routinen, handle)
495
496 atomic_kind_set => bs_env%ri_rs%atomic_kind_set
497 particle_set => bs_env%ri_rs%particle_set
498
499 IF (bs_env%unit_nr <= 0) THEN
500 CALL timestop(handle)
501 RETURN
502 END IF
503
504 nkind = SIZE(atomic_kind_set)
505 ALLOCATE (cutoff_ri_per_kind(nkind))
506 cutoff_ri_per_kind(:) = 0.0_dp
507
508 DO iatom = 1, bs_env%n_atom
509 ikind = particle_set(iatom)%atomic_kind%kind_number
510 cutoff_ri_per_kind(ikind) = max(cutoff_ri_per_kind(ikind), cutoff_ri_per_atom(iatom))
511 END DO
512
513 WRITE (bs_env%unit_nr, '(T2,A)') 'Per-kind maximum RI-RS sphere cutoff (Å):'
514 WRITE (bs_env%unit_nr, '(T4,A4,A14)') 'Kind', 'cutoff (Å)'
515 DO ikind = 1, nkind
516 WRITE (bs_env%unit_nr, '(T4,A4,F14.4)') &
517 atomic_kind_set(ikind)%element_symbol, &
518 cutoff_ri_per_kind(ikind)*angstrom
519 END DO
520 WRITE (bs_env%unit_nr, '(A)') ' '
521
522 DEALLOCATE (cutoff_ri_per_kind)
523
524 CALL timestop(handle)
525
526 END SUBROUTINE print_sphere_cutoff_table
527
528! **************************************************************************************************
529!> \brief LPT (longest-processing-time) assignment of the Z_lP atoms to workers (MPI ranks in
530!> Phase A, rank subgroups in Phase B): sort by estimated solve cost n_local_grid^3
531!> (the per-atom Cholesky dominates; the n^2 assembly terms order the atoms the same
532!> way) and greedily give each atom to the least-loaded worker.
533!> \param atom_list ...
534!> \param n_atoms ...
535!> \param n_local_grid_atom ...
536!> \param n_workers ...
537!> \param my_worker ...
538!> \param my_atoms ...
539!> \param max_over_mean ...
540! **************************************************************************************************
541 SUBROUTINE lpt_assign_atoms(atom_list, n_atoms, n_local_grid_atom, n_workers, my_worker, &
542 my_atoms, max_over_mean)
543
544 INTEGER, DIMENSION(:), INTENT(IN) :: atom_list
545 INTEGER, INTENT(IN) :: n_atoms
546 INTEGER, DIMENSION(:), INTENT(IN) :: n_local_grid_atom
547 INTEGER, INTENT(IN) :: n_workers, my_worker
548 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: my_atoms
549 REAL(kind=dp), INTENT(OUT) :: max_over_mean
550
551 CHARACTER(LEN=*), PARAMETER :: routinen = 'lpt_assign_atoms'
552
553 INTEGER :: handle, i, iw, n_mine, w_min
554 INTEGER, ALLOCATABLE, DIMENSION(:) :: mine_tmp, perm
555 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: cost, load
556
557 CALL timeset(routinen, handle)
558
559 max_over_mean = 1.0_dp
560 IF (n_atoms <= 0) THEN
561 ALLOCATE (my_atoms(0))
562 CALL timestop(handle)
563 RETURN
564 END IF
565
566 ALLOCATE (cost(n_atoms), perm(n_atoms), mine_tmp(n_atoms), load(n_workers))
567 DO i = 1, n_atoms
568 cost(i) = real(n_local_grid_atom(atom_list(i)), dp)**3
569 END DO
570 CALL sort(cost, n_atoms, perm) ! ascending; walk backwards for largest-first
571
572 load(:) = 0.0_dp
573 n_mine = 0
574 DO i = n_atoms, 1, -1
575 w_min = 1
576 DO iw = 2, n_workers
577 IF (load(iw) < load(w_min)) w_min = iw
578 END DO
579 load(w_min) = load(w_min) + cost(i)
580 IF (w_min - 1 == my_worker) THEN
581 n_mine = n_mine + 1
582 mine_tmp(n_mine) = atom_list(perm(i))
583 END IF
584 END DO
585
586 ALLOCATE (my_atoms(n_mine))
587 my_atoms(:) = mine_tmp(1:n_mine)
588 IF (sum(load) > 0.0_dp) max_over_mean = maxval(load)*real(n_workers, dp)/sum(load)
589
590 CALL timestop(handle)
591
592 END SUBROUTINE lpt_assign_atoms
593
594! **************************************************************************************************
595!> \brief Computes the dense localized right-hand side for one RI atom P,
596!>
597!> d_lP = Σ_μν ϕ_μ(r_l) ϕ_ν(r_l) (μν|P).
598!>
599!> RI atom P, OMP-threaded over (atom_j, atom_k) AO-pair blocks: per thread, build the 3c
600!> block, then contract grid-chunked pair densities into a private d_lp partial; partials
601!> are reduced into d_lp at the end.
602!> Pair screening is handled inside build_3c_integral_block_ctx via the `screened` output.
603!> \param bs_env ...
604!> \param ctx ...
605!> \param phi_val ...
606!> \param ao_col_map ...
607!> \param d_lp ...
608!> \param n_grid_total ...
609!> \param n_loc_ri ...
610!> \param atom_P ...
611!> \param max_ao_size ...
612!> \param atom_j_mepos ...
613!> \param atom_j_stride ...
614! **************************************************************************************************
615 SUBROUTINE compute_d_lp(bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid_total, n_loc_ri, atom_P, &
616 max_ao_size, atom_j_mepos, atom_j_stride)
617
618 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
619 TYPE(gw_3c_ctx_type), INTENT(IN) :: ctx
620 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: phi_val
621 INTEGER, DIMENSION(:), INTENT(IN) :: ao_col_map
622 INTEGER, INTENT(IN) :: n_grid_total, n_loc_ri
623 REAL(kind=dp), INTENT(INOUT) :: d_lp(n_grid_total, n_loc_ri)
624 INTEGER, INTENT(IN) :: atom_p, max_ao_size, atom_j_mepos, &
625 atom_j_stride
626
627 CHARACTER(LEN=*), PARAMETER :: routinen = 'compute_d_lp'
628 INTEGER, PARAMETER :: grid_chunk = 1024
629
630 INTEGER :: atom_j, atom_k, c, handle, handle_dgemm, &
631 j, jk_idx, jsize, jstart, k, ksize, &
632 kstart, l, l0, n_grid_pair, point, ri
633 INTEGER, ALLOCATABLE :: grid_index(:)
634 LOGICAL :: screened
635 LOGICAL, ALLOCATABLE :: skip_grid_point(:, :)
636 REAL(kind=dp) :: pair_factor
637 REAL(kind=dp), ALLOCATABLE :: grid_result(:, :)
638 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: d_lp_prv, int_2d_prv, rho_chunk
639 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :) :: int_3c_prv
640 TYPE(gw_3c_ws_type) :: ws
641
642 CALL timeset(routinen, handle)
643
644 !$OMP PARALLEL DEFAULT(NONE) &
645 !$OMP SHARED(skip_grid_point, bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid_total, n_loc_ri, atom_P, max_ao_size, &
646 !$OMP atom_j_mepos, atom_j_stride) &
647 !$OMP PRIVATE(grid_index, grid_result, n_grid_pair, point, pair_factor, &
648 !$OMP atom_j, atom_k, c, handle_dgemm, j, jk_idx, jsize, jstart, k, ksize, kstart, &
649 !$OMP l, l0, ri, screened, d_lp_prv, int_2d_prv, rho_chunk, int_3c_prv, ws)
650
651 CALL gw_3c_ws_create(ws, ctx)
652 ALLOCATE (int_3c_prv(max_ao_size, max_ao_size, n_loc_ri))
653 ALLOCATE (int_2d_prv(max_ao_size*max_ao_size, n_loc_ri))
654 ALLOCATE (rho_chunk(grid_chunk, max_ao_size*max_ao_size))
655 ALLOCATE (d_lp_prv(n_grid_total, n_loc_ri))
656 ALLOCATE (grid_index(n_grid_total), grid_result(grid_chunk, n_loc_ri))
657 d_lp_prv(:, :) = 0.0_dp
658
659 !$OMP SINGLE
660 ALLOCATE (skip_grid_point(n_grid_total, bs_env%n_atom))
661 CALL compute_skip_grid_point(bs_env, phi_val, ao_col_map, skip_grid_point)
662 !$OMP END SINGLE
663
664 ! MPI assigns each unordered pair through its first atom; OpenMP divides those atoms.
665 ! Skip only exact-zero pair-grid support, without a new screening threshold.
666 !$OMP DO SCHEDULE(DYNAMIC)
667 DO atom_j = atom_j_mepos + 1, bs_env%n_atom, atom_j_stride
668 DO atom_k = atom_j, bs_env%n_atom
669 jstart = ao_col_map(bs_env%i_ao_start_from_atom(atom_j))
670 kstart = ao_col_map(bs_env%i_ao_start_from_atom(atom_k))
671 IF (jstart == 0 .OR. kstart == 0) cycle
672 jsize = bs_env%i_ao_end_from_atom(atom_j) - bs_env%i_ao_start_from_atom(atom_j) + 1
673 ksize = bs_env%i_ao_end_from_atom(atom_k) - bs_env%i_ao_start_from_atom(atom_k) + 1
674
675 n_grid_pair = 0
676 DO point = 1, n_grid_total
677 IF (skip_grid_point(point, atom_j) .OR. skip_grid_point(point, atom_k)) cycle
678 n_grid_pair = n_grid_pair + 1
679 grid_index(n_grid_pair) = point
680 END DO
681 IF (n_grid_pair == 0) cycle
682 ! (μν|P) = (νμ|P): distinct atom pairs contribute twice.
683 pair_factor = 1.0_dp
684 IF (atom_j /= atom_k) pair_factor = 2.0_dp
685
686 int_3c_prv(1:jsize, 1:ksize, 1:n_loc_ri) = 0.0_dp
687
688 ! Compute B_{μν,P} = (μν|P); ctx-internal triangle-inequality screening on
689 ! kind_radius sets `screened=.TRUE.` for negligible triples.
690 CALL build_3c_integral_block_ctx(int_3c_prv(1:jsize, 1:ksize, 1:n_loc_ri), &
691 ctx, ws, atom_j=atom_j, atom_k=atom_k, atom_i=atom_p, &
692 screened=screened)
693
694 IF (screened) cycle
695
696 ! Flatten 3D B_{μν, P} tensor to 2D B_{(μν), P} matrix for BLAS
697 DO ri = 1, n_loc_ri
698 DO k = 1, ksize
699 DO j = 1, jsize
700 jk_idx = (k - 1)*jsize + j
701 int_2d_prv(jk_idx, ri) = int_3c_prv(j, k, ri)
702 END DO
703 END DO
704 END DO
705
706 ! Pair density ρ(l, μν) = ϕ_μ(r_l) ϕ_ν(r_l) in grid chunks, contracted on the fly:
707 ! d_{l,P} += ρ(l, μν) B_{(μν),P} (dgemm runs serially inside the parallel region)
708 DO l0 = 1, n_grid_pair, grid_chunk
709 c = min(grid_chunk, n_grid_pair - l0 + 1)
710 DO k = 1, ksize
711 DO j = 1, jsize
712 jk_idx = (k - 1)*jsize + j
713 DO l = 1, c
714 point = grid_index(l0 + l - 1)
715 rho_chunk(l, jk_idx) = phi_val(point, jstart + j - 1)* &
716 phi_val(point, kstart + k - 1)
717 END DO
718 END DO
719 END DO
720 CALL timeset(routinen//"_dgemm", handle_dgemm)
721 CALL dgemm("N", "N", c, n_loc_ri, jsize*ksize, &
722 pair_factor, rho_chunk, grid_chunk, &
723 int_2d_prv, max_ao_size*max_ao_size, &
724 0.0_dp, grid_result, grid_chunk)
725 DO ri = 1, n_loc_ri
726 DO l = 1, c
727 point = grid_index(l0 + l - 1)
728 d_lp_prv(point, ri) = d_lp_prv(point, ri) + grid_result(l, ri)
729 END DO
730 END DO
731 CALL timestop(handle_dgemm)
732 END DO
733 END DO
734 END DO
735 !$OMP END DO
736
737 !$OMP CRITICAL (compute_d_lp_reduce)
738 d_lp(1:n_grid_total, 1:n_loc_ri) = d_lp(1:n_grid_total, 1:n_loc_ri) + &
739 d_lp_prv(1:n_grid_total, 1:n_loc_ri)
740 !$OMP END CRITICAL (compute_d_lp_reduce)
741
742 DEALLOCATE (int_3c_prv, int_2d_prv, rho_chunk, d_lp_prv, grid_index, grid_result)
743 CALL gw_3c_ws_release(ws)
744
745 !$OMP SINGLE
746 DEALLOCATE (skip_grid_point)
747 !$OMP END SINGLE
748
749 !$OMP END PARALLEL
750
751 CALL timestop(handle)
752
753 END SUBROUTINE compute_d_lp
754
755! **************************************************************************************************
756!> \brief Marks grid points where all stored AO values of an atom are exactly zero.
757!> \param bs_env ...
758!> \param phi_val ...
759!> \param ao_col_map ...
760!> \param skip_grid_point ...
761! **************************************************************************************************
762 SUBROUTINE compute_skip_grid_point(bs_env, phi_val, ao_col_map, skip_grid_point)
763
764 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
765 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: phi_val
766 INTEGER, DIMENSION(:), INTENT(IN) :: ao_col_map
767 LOGICAL, DIMENSION(:, :), INTENT(OUT) :: skip_grid_point
768
769 INTEGER :: atom, first_ao, number_of_aos
770
771 skip_grid_point(:, :) = .true.
772 DO atom = 1, bs_env%n_atom
773 first_ao = ao_col_map(bs_env%i_ao_start_from_atom(atom))
774 IF (first_ao == 0) cycle
775 number_of_aos = bs_env%i_ao_end_from_atom(atom) - bs_env%i_ao_start_from_atom(atom) + 1
776 skip_grid_point(:, atom) = all(phi_val(:, first_ao:first_ao + number_of_aos - 1) == 0.0_dp, dim=2)
777 END DO
778
779 END SUBROUTINE compute_skip_grid_point
780
781! **************************************************************************************************
782!> \brief Computes the RI-RS matrix Z_lP for an automatically optimized RI basis.
783!>
784!> The fitting coefficients Z_lP satisfy
785!>
786!> Σ_l' D_ll' Z_l'P = d_lP,
787!> D_ll' = [Σ_μ ϕ_μ(r_l) ϕ_μ(r_l')]²,
788!> d_lP = Σ_μν ϕ_μ(r_l) ϕ_ν(r_l) (μν|P).
789!>
790!> For the standard RI-RS fit, P is an atom-centered RI function. Here an optimized
791!> function may contain reference functions on neighboring atoms,
792!>
793!> φ_p(r) = Σ_A Σ_{P∈A} U_Pp^A φ_P^A(r),
794!>
795!> so all atomic contributions to d_lp must be accumulated before solving for Z_lp.
796!> If every optimized column uses the complete RI-RS grid, all columns are solved in one
797!> system. Otherwise, each atom-blocked column set is fitted on its own integration sphere;
798!> grid points outside that sphere are excluded from its fitting equations.
799!> \param qs_env ...
800!> \param bs_env ...
801!> \param ri_rs_grid_points ...
802!> \param mat_phi_mu_l ...
803!> \param mat_Z_lP ...
804! **************************************************************************************************
805 SUBROUTINE compute_z_lp_auto_ri(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_Z_lP)
806 TYPE(qs_environment_type), POINTER :: qs_env
807 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
808 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ri_rs_grid_points
809 TYPE(dbcsr_type), INTENT(INOUT) :: mat_phi_mu_l
810 TYPE(dbcsr_type), INTENT(OUT) :: mat_z_lp
811
812 CHARACTER(LEN=*), PARAMETER :: key = 'PROPERTIES%BANDSTRUCTURE%GW%PRINT%RESTART', &
813 routinen = 'compute_Z_lP_auto_ri'
814
815 INTEGER :: ab_block, atom_a, atom_b, block_size_b, column_first, first_p_ab, fit_atom, &
816 handle, handle_dpotrf, handle_dpotrs, info, max_ao_size, max_nri_ref, mypcol, myprow, &
817 n_ao_total, n_ao_used, n_done, n_my_atoms, n_to_a, natom, ncol, ngrid, nri, nri_ref_a, &
818 nri_ref_b, output_offset, ri_atom
819 INTEGER, ALLOCATABLE, DIMENSION(:) :: ao_col_map, local_grid_idx, row_offset
820 INTEGER, DIMENSION(:), POINTER :: col_dist_ri, ri_blk_sizes, &
821 row_dist_grid, row_size_grid
822 LOGICAL :: ab_block_local, common_grid_available, &
823 have_fitted_columns, &
824 reuse_atomic_integrals
825 LOGICAL, ALLOCATABLE, DIMENSION(:) :: active_atom
826 REAL(kind=dp) :: cutoff_ri, item_start_time, r_c, t1
827 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: d_vec
828 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: d_local, d_lp_all, d_lp_local, &
829 phi_local, u_pp_ab
830 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :) :: u_pp_by_atom
831 REAL(kind=dp), DIMENSION(3) :: center
832 TYPE(cell_type), POINTER :: cell
833 TYPE(cp_logger_type), POINTER :: logger
834 TYPE(dbcsr_distribution_type) :: dist_z
835 TYPE(dbcsr_type) :: mat_rhs
836 TYPE(gw_3c_ctx_type) :: ctx_3c
837 TYPE(mp_para_env_type), POINTER :: para_env, para_env_col
838 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
839 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
840 TYPE(section_vals_type), POINTER :: input
841
842 CALL timeset(routinen, handle)
843 t1 = m_walltime()
844 IF (bs_env%unit_nr > 0) THEN
845 WRITE (bs_env%unit_nr, '(A)') ' '
846 WRITE (bs_env%unit_nr, '(T2,A)') 'Started computing Z_lP'
847 CALL m_flush(bs_env%unit_nr)
848 END IF
849 CALL get_qs_env(qs_env, para_env=para_env, particle_set=particle_set, input=input, &
850 qs_kind_set=qs_kind_set, cell=cell)
851 NULLIFY (para_env_col)
852
853 natom = bs_env%n_atom
854 n_ao_total = bs_env%i_ao_end_from_atom(natom)
855 cpassert(bs_env%auto_ri%AB_block_count > 0)
856 cpassert(SIZE(particle_set) == natom)
857
858 CALL prepare_z_lp_auto_ri(bs_env, mat_phi_mu_l, mat_z_lp, dist_z, row_size_grid, &
859 row_dist_grid, col_dist_ri, ri_blk_sizes, row_offset, &
860 myprow, mypcol, max_ao_size)
861
862 CALL gw_3c_ctx_create(ctx_3c, bs_env, bs_env%ri_metric, &
863 basis_j=bs_env%basis_set_AO, basis_k=bs_env%basis_set_AO, &
864 basis_i=bs_env%basis_set_RI)
865
866 ! Check whether one grid can represent d_lp for every optimized atomic column block.
867 CALL common_z_lp_grid_available(bs_env, ri_rs_grid_points, &
868 common_grid_available, have_fitted_columns)
869
870 IF (common_grid_available .AND. have_fitted_columns) THEN
871 ! Evaluate ϕ_μ(r_l) once on the common grid.
872 CALL build_phi_on_complete_grid(bs_env, qs_kind_set, &
873 ri_rs_grid_points, n_ao_total, local_grid_idx, ngrid, &
874 phi_local, ao_col_map, n_ao_used)
875 nri = sum(ri_blk_sizes)
876 ALLOCATE (d_lp_all(ngrid, nri), source=0.0_dp)
877 ! d_lp = Σ_A Σ_{P∈A} d_lP U_Pp for every optimized RI function q.
878 CALL compute_d_lp_auto_ri_batch(bs_env, ctx_3c, phi_local, ao_col_map, d_lp_all, ngrid, &
879 max_ao_size, para_env%mepos, para_env%num_pe)
880 CALL para_env%sum(d_lp_all)
881 ALLOCATE (d_vec(ngrid))
882 ! D_ll' = [Σ_μ ϕ_μ(r_l) ϕ_μ(r_l')]², followed by D Z = d.
883 CALL build_gram_jacobi_blas(phi_local, ngrid, n_ao_used, bs_env%ri_rs%tikhonov, &
884 d_local, d_vec)
885 CALL scale_rows_by_diag(d_lp_all, d_vec, ngrid, nri)
886 CALL timeset(routinen//'_dpotrf', handle_dpotrf)
887 CALL dpotrf('L', ngrid, d_local, ngrid, info)
888 CALL timestop(handle_dpotrf)
889 cpassert(info == 0)
890 CALL timeset(routinen//'_dpotrs', handle_dpotrs)
891 CALL dpotrs('L', ngrid, nri, d_local, ngrid, d_lp_all, ngrid, info)
892 CALL timestop(handle_dpotrs)
893 cpassert(info == 0)
894 CALL scale_rows_by_diag(d_lp_all, d_vec, ngrid, nri)
895
896 DO ab_block = 1, bs_env%auto_ri%AB_block_count
897 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
898 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
899 ab_block_local = col_dist_ri(atom_a) == mypcol
900 IF (atom_b /= atom_a) ab_block_local = ab_block_local .OR. col_dist_ri(atom_b) == mypcol
901 IF (.NOT. ab_block_local) cycle
902 ncol = bs_env%auto_ri%AB_size_opt_RI(ab_block)
903 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
904 IF (n_to_a > 0 .AND. col_dist_ri(atom_a) == mypcol) THEN
905 output_offset = sum(ri_blk_sizes(:atom_a - 1)) + &
906 bs_env%auto_ri%AB_first_p_A(ab_block) - 1
907 CALL add_z_lp_columns(mat_z_lp, &
908 d_lp_all(:, output_offset + 1:output_offset + n_to_a), &
909 local_grid_idx, ngrid, atom_a, &
910 bs_env%auto_ri%AB_first_p_A(ab_block), &
911 ri_blk_sizes(atom_a), row_size_grid, row_offset, &
912 row_dist_grid, &
913 myprow, bs_env%eps_filter)
914 END IF
915 IF (n_to_a < ncol) THEN
916 cpassert(atom_b /= atom_a)
917 IF (col_dist_ri(atom_b) == mypcol) THEN
918 block_size_b = ri_blk_sizes(atom_b)
919 output_offset = sum(ri_blk_sizes(:atom_b - 1)) + &
920 bs_env%auto_ri%AB_first_p_B(ab_block) - 1
921 CALL add_z_lp_columns(mat_z_lp, &
922 d_lp_all(:, output_offset + 1: &
923 output_offset + ncol - n_to_a), &
924 local_grid_idx, ngrid, atom_b, &
925 bs_env%auto_ri%AB_first_p_B(ab_block), block_size_b, &
926 row_size_grid, row_offset, row_dist_grid, myprow, &
927 bs_env%eps_filter)
928 END IF
929 END IF
930 END DO
931 DEALLOCATE (d_local, d_vec, d_lp_all, local_grid_idx, phi_local, ao_col_map)
932 ELSE
933 reuse_atomic_integrals = &
934 bs_env%ri_rs%cutoff_radius_ri_ao <= 0.0_dp .OR. &
935 bs_env%ri_rs%cutoff_radius_ri_ao <= &
936 minval(bs_env%ri_rs%radius_ao_per_atom)
937 IF (reuse_atomic_integrals) THEN
938 ! Form d_lp = Σ_A Σ_{P∈A} d_lP U_Pp before fitting each atomic column block.
939 CALL compute_auto_ri_d_lp(qs_env, bs_env, ctx_3c, &
940 ri_rs_grid_points, mat_phi_mu_l, mat_rhs, &
941 max_ao_size)
942 CALL dbcsr_release(mat_z_lp)
943 CALL dbcsr_create(mat_z_lp, name='mat_Z_lP localized AA/AB', dist=dist_z, &
944 matrix_type=dbcsr_type_no_symmetry, row_blk_size=row_size_grid, &
945 col_blk_size=ri_blk_sizes)
946 ! Solve Σ_l' D_ll' Z_l'q = d_lp on each atomic fitting grid.
947 CALL fit_auto_ri_z_lp(qs_env, bs_env, ri_rs_grid_points, mat_rhs, mat_z_lp)
948 CALL dbcsr_release(mat_rhs)
949 ELSE
950 ALLOCATE (para_env_col)
951 CALL para_env_col%from_split(para_env, mypcol)
952 n_my_atoms = 0
953 DO fit_atom = 1, natom
954 IF (col_dist_ri(fit_atom) /= mypcol) cycle
955 IF (ri_blk_sizes(fit_atom) == 0) cycle
956 n_my_atoms = n_my_atoms + 1
957 END DO
958 n_done = 0
959 max_nri_ref = 0
960 DO ri_atom = 1, natom
961 max_nri_ref = max(max_nri_ref, get_ref_ri_size(bs_env, ri_atom))
962 END DO
963 DO fit_atom = 1, natom
964 IF (col_dist_ri(fit_atom) /= mypcol) cycle
965 ncol = ri_blk_sizes(fit_atom)
966 IF (ncol == 0) cycle
967 item_start_time = m_walltime()
968 ALLOCATE (u_pp_by_atom(max_nri_ref, ncol, natom), source=0.0_dp)
969 ALLOCATE (active_atom(natom), source=.false.)
970
971 DO ab_block = 1, bs_env%auto_ri%AB_block_count
972 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
973 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
974 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
975 IF (fit_atom == atom_a .AND. n_to_a > 0) THEN
976 column_first = bs_env%auto_ri%AB_first_p_A(ab_block)
977 first_p_ab = 1
978 ncol = n_to_a
979 ELSE IF (fit_atom == atom_b .AND. &
980 n_to_a < bs_env%auto_ri%AB_size_opt_RI(ab_block)) THEN
981 column_first = bs_env%auto_ri%AB_first_p_B(ab_block)
982 first_p_ab = n_to_a + 1
983 ncol = bs_env%auto_ri%AB_size_opt_RI(ab_block) - n_to_a
984 ELSE
985 cycle
986 END IF
987 CALL get_u_pp_ab(bs_env%auto_ri, ab_block, u_pp_ab)
988
989 nri_ref_a = get_ref_ri_size(bs_env, atom_a)
990 u_pp_by_atom(1:nri_ref_a, &
991 column_first:column_first + ncol - 1, atom_a) = &
992 u_pp_ab( &
993 1:nri_ref_a, first_p_ab:first_p_ab + ncol - 1)
994 active_atom(atom_a) = .true.
995 IF (atom_b /= atom_a) THEN
996 nri_ref_b = get_ref_ri_size(bs_env, atom_b)
997 u_pp_by_atom(1:nri_ref_b, &
998 column_first:column_first + ncol - 1, atom_b) = &
999 u_pp_ab( &
1000 nri_ref_a + 1:nri_ref_a + nri_ref_b, &
1001 first_p_ab:first_p_ab + ncol - 1)
1002 active_atom(atom_b) = .true.
1003 END IF
1004 DEALLOCATE (u_pp_ab)
1005 END DO
1006
1007 center = particle_set(fit_atom)%r
1008 IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp) THEN
1009 cutoff_ri = bs_env%ri_rs%cutoff_radius_ri_rs
1010 ELSE
1011 r_c = bs_env%ri_metric%cutoff_radius
1012 cutoff_ri = 0.0_dp
1013 DO ri_atom = 1, natom
1014 IF (.NOT. active_atom(ri_atom)) cycle
1015 cutoff_ri = max(cutoff_ri, &
1016 r_c + bs_env%ri_rs%radius_ri_per_atom(ri_atom) + &
1017 norm2(center - particle_set(ri_atom)%r))
1018 END DO
1019 END IF
1020 CALL build_phi_on_sphere(bs_env, qs_kind_set, &
1021 ri_rs_grid_points, fit_atom, cutoff_ri, n_ao_total, &
1022 local_grid_idx, ngrid, phi_local, ao_col_map, n_ao_used, &
1023 center=center)
1024 ncol = ri_blk_sizes(fit_atom)
1025 ALLOCATE (d_lp_local(ngrid, ncol), source=0.0_dp)
1026 ! d_lp = Σ_A Σ_{P∈A} d_lP U_Pp on the grid of this atomic column block.
1027 CALL compute_d_lp_auto_ri_atoms(bs_env, ctx_3c, phi_local, ao_col_map, &
1028 d_lp_local, ngrid, u_pp_by_atom, &
1029 active_atom, max_ao_size, &
1030 para_env_col%mepos, para_env_col%num_pe)
1031 CALL para_env_col%sum(d_lp_local)
1032 ALLOCATE (d_vec(ngrid))
1033 ! D_ll' = [Σ_μ ϕ_μ(r_l) ϕ_μ(r_l')]², followed by D Z = d.
1034 CALL build_gram_jacobi_blas(phi_local, ngrid, n_ao_used, bs_env%ri_rs%tikhonov, &
1035 d_local, d_vec)
1036 CALL scale_rows_by_diag(d_lp_local, d_vec, ngrid, ncol)
1037 CALL timeset(routinen//'_dpotrf', handle_dpotrf)
1038 CALL dpotrf('L', ngrid, d_local, ngrid, info)
1039 CALL timestop(handle_dpotrf)
1040 cpassert(info == 0)
1041 CALL timeset(routinen//'_dpotrs', handle_dpotrs)
1042 CALL dpotrs('L', ngrid, ncol, d_local, ngrid, d_lp_local, ngrid, info)
1043 CALL timestop(handle_dpotrs)
1044 cpassert(info == 0)
1045 CALL scale_rows_by_diag(d_lp_local, d_vec, ngrid, ncol)
1046 CALL add_z_lp_columns(mat_z_lp, d_lp_local, local_grid_idx, ngrid, fit_atom, 1, &
1047 ri_blk_sizes(fit_atom), row_size_grid, row_offset, &
1048 row_dist_grid, &
1049 myprow, bs_env%eps_filter)
1050 DEALLOCATE (d_local, d_vec, d_lp_local, local_grid_idx, phi_local, ao_col_map)
1051 DEALLOCATE (u_pp_by_atom, active_atom)
1052 n_done = n_done + 1
1053 CALL print_z_lp_progress(bs_env, n_done, n_my_atoms, &
1054 m_walltime() - item_start_time)
1055 END DO
1056 CALL para_env_col%free()
1057 DEALLOCATE (para_env_col)
1058 END IF
1059 END IF
1060 CALL gw_3c_ctx_release(ctx_3c)
1061
1062 CALL dbcsr_filter(mat_z_lp, bs_env%eps_filter)
1063 CALL dbcsr_finalize(mat_z_lp)
1064 CALL para_env%sync()
1065 CALL print_z_lp_progress(bs_env, natom, natom, m_walltime() - t1, &
1066 all_mpi_ranks=.true.)
1067 logger => cp_get_default_logger()
1068 IF (btest(cp_print_key_should_output(logger%iter_info, input, key), cp_p_file)) THEN
1069 CALL dbcsr_binary_write(matrix=mat_z_lp, filepath=trim(bs_env%prefix)//'Z_lP.matrix')
1070 END IF
1071
1072 DEALLOCATE (row_offset, ri_blk_sizes, col_dist_ri)
1073 CALL dbcsr_distribution_release(dist_z)
1074 CALL timestop(handle)
1075
1076 END SUBROUTINE compute_z_lp_auto_ri
1077
1078! **************************************************************************************************
1079!> \brief Prints completed Z_lP atoms and execution time from the printing rank.
1080!> \param bs_env ...
1081!> \param n_done Number of atoms completed by the printing rank.
1082!> \param n_total Total number of atoms assigned to the printing rank.
1083!> \param execution_time Wall-clock time used for the reported work.
1084!> \param all_mpi_ranks Whether all MPI ranks have completed the calculation.
1085! **************************************************************************************************
1086 SUBROUTINE print_z_lp_progress(bs_env, n_done, n_total, execution_time, all_mpi_ranks)
1087 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1088 INTEGER, INTENT(IN) :: n_done, n_total
1089 REAL(kind=dp), INTENT(IN) :: execution_time
1090 LOGICAL, INTENT(IN), OPTIONAL :: all_mpi_ranks
1091
1092 CHARACTER(LEN=*), PARAMETER :: routinen = 'print_Z_lP_progress'
1093
1094 INTEGER :: handle
1095 LOGICAL :: completed
1096
1097 CALL timeset(routinen, handle)
1098
1099 IF (bs_env%unit_nr > 0) THEN
1100 completed = .false.
1101 IF (PRESENT(all_mpi_ranks)) completed = all_mpi_ranks
1102 IF (completed) THEN
1103 WRITE (bs_env%unit_nr, '(T2,A,T58,A,F7.1,A,/)') &
1104 'Computed Z_lP (all MPI ranks) for all atoms,', &
1105 'Execution time', execution_time, ' s'
1106 ELSE
1107 WRITE (bs_env%unit_nr, '(T2,A,I11,A,I3,A,F7.1,A)') &
1108 'Computed Z_lP (MPI rank 0) for atom', n_done, ' /', n_total, &
1109 ', Execution time', execution_time, ' s'
1110 END IF
1111 CALL m_flush(bs_env%unit_nr)
1112 END IF
1113
1114 CALL timestop(handle)
1115
1116 END SUBROUTINE print_z_lp_progress
1117
1118! **************************************************************************************************
1119!> \brief Prepares the distributed Z_lP matrix and its atom-blocked column layout. Column block A
1120!> contains all optimized functions assigned to atom A. Every local block is reserved once
1121!> because several AA/AB contraction blocks may contribute to the same block.
1122!> \param bs_env ...
1123!> \param mat_phi_mu_l ...
1124!> \param mat_Z_lP ...
1125!> \param dist_Z ...
1126!> \param row_size_grid ...
1127!> \param row_dist_grid ...
1128!> \param col_dist_ri ...
1129!> \param ri_blk_sizes ...
1130!> \param row_offset ...
1131!> \param myprow ...
1132!> \param mypcol ...
1133!> \param max_ao_size ...
1134! **************************************************************************************************
1135 SUBROUTINE prepare_z_lp_auto_ri(bs_env, mat_phi_mu_l, mat_Z_lP, dist_Z, row_size_grid, &
1136 row_dist_grid, col_dist_ri, ri_blk_sizes, row_offset, &
1137 myprow, mypcol, max_ao_size)
1138 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1139 TYPE(dbcsr_type), INTENT(IN) :: mat_phi_mu_l
1140 TYPE(dbcsr_type), INTENT(OUT) :: mat_z_lp
1141 TYPE(dbcsr_distribution_type), INTENT(OUT) :: dist_z
1142 INTEGER, DIMENSION(:), POINTER :: row_size_grid, row_dist_grid, &
1143 col_dist_ri, ri_blk_sizes
1144 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: row_offset
1145 INTEGER, INTENT(OUT) :: myprow, mypcol, max_ao_size
1146
1147 CHARACTER(LEN=*), PARAMETER :: routinen = 'prepare_Z_lP_auto_ri'
1148
1149 INTEGER :: handle, i_blk, iatom, npcol
1150 TYPE(dbcsr_distribution_type) :: dist_phi
1151
1152 CALL timeset(routinen, handle)
1153
1154 CALL dbcsr_get_info(mat_phi_mu_l, row_blk_size=row_size_grid, distribution=dist_phi)
1155 CALL dbcsr_distribution_get(dist_phi, row_dist=row_dist_grid, npcols=npcol, &
1156 myprow=myprow, mypcol=mypcol)
1157 ALLOCATE (row_offset(SIZE(row_size_grid)))
1158 row_offset(1) = 0
1159 DO i_blk = 2, SIZE(row_size_grid)
1160 row_offset(i_blk) = row_offset(i_blk - 1) + row_size_grid(i_blk - 1)
1161 END DO
1162
1163 ALLOCATE (ri_blk_sizes(bs_env%n_atom), col_dist_ri(bs_env%n_atom))
1164 ri_blk_sizes = bs_env%auto_ri%sizes_opt_RI
1165 DO iatom = 1, bs_env%n_atom
1166 col_dist_ri(iatom) = mod(iatom - 1, npcol)
1167 END DO
1168 CALL dbcsr_distribution_new(dist_z, template=dist_phi, row_dist=row_dist_grid, &
1169 col_dist=col_dist_ri)
1170 CALL dbcsr_create(mat_z_lp, name='mat_Z_lP localized AA/AB', dist=dist_z, &
1171 matrix_type=dbcsr_type_no_symmetry, row_blk_size=row_size_grid, &
1172 col_blk_size=ri_blk_sizes)
1173 CALL dbcsr_reserve_all_blocks(mat_z_lp)
1174 CALL dbcsr_set(mat_z_lp, 0.0_dp)
1175
1176 max_ao_size = 0
1177 DO iatom = 1, bs_env%n_atom
1178 max_ao_size = max(max_ao_size, bs_env%i_ao_end_from_atom(iatom) - &
1179 bs_env%i_ao_start_from_atom(iatom) + 1)
1180 END DO
1181
1182 CALL timestop(handle)
1183
1184 END SUBROUTINE prepare_z_lp_auto_ri
1185
1186! **************************************************************************************************
1187!> \brief Tests whether every fitted atomic block can use the complete RI-RS grid.
1188!>
1189!> For a block centered on A, every grid point must satisfy
1190!>
1191!> |r_l - R_A| <= R_A^fit,
1192!>
1193!> and every atom B whose AOs can contribute must satisfy
1194!>
1195!> |R_B - R_A| <= R_B^AO + R_A^fit.
1196!>
1197!> Pair-midpoint grids do not satisfy this atom-centered criterion in general.
1198!> \param bs_env ...
1199!> \param ri_rs_grid_points ...
1200!> \param common_grid_available ...
1201!> \param have_fitted_columns ...
1202! **************************************************************************************************
1203 SUBROUTINE common_z_lp_grid_available(bs_env, ri_rs_grid_points, &
1204 common_grid_available, have_fitted_columns)
1205 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1206 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ri_rs_grid_points
1207 LOGICAL, INTENT(OUT) :: common_grid_available, &
1208 have_fitted_columns
1209
1210 CHARACTER(LEN=*), PARAMETER :: routinen = 'common_Z_lP_grid_available'
1211
1212 INTEGER :: ab_block, atom_a, atom_b, fit_atom, &
1213 handle, iatom, igrid, n_to_a, natom
1214 LOGICAL, ALLOCATABLE, DIMENSION(:) :: active_atom
1215 REAL(kind=dp) :: cutoff_ri
1216 REAL(kind=dp), DIMENSION(3) :: center
1217 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1218
1219 CALL timeset(routinen, handle)
1220
1221 particle_set => bs_env%ri_rs%particle_set
1222 natom = bs_env%n_atom
1223 common_grid_available = .true.
1224 have_fitted_columns = .false.
1225 ALLOCATE (active_atom(natom))
1226 DO fit_atom = 1, natom
1227 IF (bs_env%auto_ri%sizes_opt_RI(fit_atom) == 0) cycle
1228 have_fitted_columns = .true.
1229 active_atom = .false.
1230 DO ab_block = 1, bs_env%auto_ri%AB_block_count
1231 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1232 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1233 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
1234 IF (.NOT. (fit_atom == atom_a .AND. n_to_a > 0) .AND. &
1235 .NOT. (fit_atom == atom_b .AND. &
1236 n_to_a < bs_env%auto_ri%AB_size_opt_RI(ab_block))) cycle
1237 active_atom(atom_a) = .true.
1238 IF (atom_b /= atom_a) active_atom(atom_b) = .true.
1239 END DO
1240
1241 center = particle_set(fit_atom)%r
1242 IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp) THEN
1243 cutoff_ri = bs_env%ri_rs%cutoff_radius_ri_rs
1244 ELSE
1245 cutoff_ri = 0.0_dp
1246 DO iatom = 1, natom
1247 IF (.NOT. active_atom(iatom)) cycle
1248 cutoff_ri = max(cutoff_ri, bs_env%ri_metric%cutoff_radius + &
1249 bs_env%ri_rs%radius_ri_per_atom(iatom) + &
1250 norm2(center - particle_set(iatom)%r))
1251 END DO
1252 END IF
1253
1254 DO igrid = 1, bs_env%ri_rs%n_grid_points
1255 IF (norm2(ri_rs_grid_points(1:3, igrid) - center) > cutoff_ri) THEN
1256 common_grid_available = .false.
1257 EXIT
1258 END IF
1259 END DO
1260 IF (.NOT. common_grid_available) EXIT
1261
1262 DO iatom = 1, natom
1263 IF (norm2(particle_set(iatom)%r - center) > &
1264 bs_env%ri_rs%radius_ao_per_atom(iatom) + cutoff_ri) THEN
1265 common_grid_available = .false.
1266 EXIT
1267 END IF
1268 END DO
1269 IF (.NOT. common_grid_available) EXIT
1270 END DO
1271 DEALLOCATE (active_atom)
1272
1273 CALL timestop(handle)
1274
1275 END SUBROUTINE common_z_lp_grid_available
1276
1277! **************************************************************************************************
1278!> \brief Evaluates the AO collocation matrix on the complete RI-RS grid,
1279!>
1280!> ϕ_lμ = ϕ_μ(r_l), l = 1, ..., N_grid.
1281!>
1282!> "Complete common grid" means that the same full set of grid points is valid for every
1283!> optimized RI column block. The enclosing sphere is only an implementation device passed
1284!> to build_phi_on_sphere; it contains every r_l and every AO center, so its chosen center
1285!> does not select an AA or AB contraction.
1286!> \param bs_env ...
1287!> \param qs_kind_set ...
1288!> \param ri_rs_grid_points ...
1289!> \param n_ao_total ...
1290!> \param local_grid_idx ...
1291!> \param ngrid ...
1292!> \param phi_local ...
1293!> \param ao_col_map ...
1294!> \param n_ao_used ...
1295! **************************************************************************************************
1296 SUBROUTINE build_phi_on_complete_grid(bs_env, qs_kind_set, &
1297 ri_rs_grid_points, n_ao_total, local_grid_idx, ngrid, &
1298 phi_local, ao_col_map, n_ao_used)
1299 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1300 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1301 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ri_rs_grid_points
1302 INTEGER, INTENT(IN) :: n_ao_total
1303 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: local_grid_idx
1304 INTEGER, INTENT(OUT) :: ngrid
1305 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :), &
1306 INTENT(OUT) :: phi_local
1307 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: ao_col_map
1308 INTEGER, INTENT(OUT) :: n_ao_used
1309
1310 CHARACTER(LEN=*), PARAMETER :: routinen = 'build_phi_on_complete_grid'
1311
1312 INTEGER :: handle, iatom, igrid, reference_atom
1313 REAL(kind=dp) :: cutoff_ri
1314 REAL(kind=dp), DIMENSION(3) :: center
1315 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1316
1317 CALL timeset(routinen, handle)
1318
1319 particle_set => bs_env%ri_rs%particle_set
1320 reference_atom = 1
1321 center = particle_set(reference_atom)%r
1322 cutoff_ri = 0.0_dp
1323 DO igrid = 1, bs_env%ri_rs%n_grid_points
1324 cutoff_ri = max(cutoff_ri, norm2(ri_rs_grid_points(1:3, igrid) - center))
1325 END DO
1326 DO iatom = 1, bs_env%n_atom
1327 cutoff_ri = max(cutoff_ri, norm2(particle_set(iatom)%r - center))
1328 END DO
1329 cutoff_ri = cutoff_ri + 1.0_dp
1330
1331 CALL build_phi_on_sphere(bs_env, qs_kind_set, &
1332 ri_rs_grid_points, reference_atom, cutoff_ri, n_ao_total, &
1333 local_grid_idx, ngrid, phi_local, ao_col_map, n_ao_used, &
1334 center=center)
1335
1336 CALL timestop(handle)
1337
1338 END SUBROUTINE build_phi_on_complete_grid
1339
1340! **************************************************************************************************
1341!> \brief Writes Z_l,p0+p += z_lp into the process-owned grid-row blocks of one atomic column
1342!> block. The routine performs no explicit MPI communication; DBCSR summation combines
1343!> contributions when a block receives columns from more than one contraction group.
1344!> \param mat_Z_lP ...
1345!> \param z_block ...
1346!> \param local_grid_idx ...
1347!> \param n_local_grid ...
1348!> \param atom_index ...
1349!> \param first_column ...
1350!> \param atom_block_size ...
1351!> \param r_blk_sizes ...
1352!> \param row_offset ...
1353!> \param row_dist ...
1354!> \param myprow ...
1355!> \param eps_filter ...
1356! **************************************************************************************************
1357 SUBROUTINE add_z_lp_columns(mat_Z_lP, z_block, local_grid_idx, n_local_grid, atom_index, &
1358 first_column, atom_block_size, r_blk_sizes, row_offset, row_dist, &
1359 myprow, eps_filter)
1360
1361 TYPE(dbcsr_type), INTENT(INOUT) :: mat_z_lp
1362 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: z_block
1363 INTEGER, DIMENSION(:), INTENT(IN) :: local_grid_idx
1364 INTEGER, INTENT(IN) :: n_local_grid, atom_index, first_column, &
1365 atom_block_size
1366 INTEGER, DIMENSION(:), INTENT(IN) :: r_blk_sizes, row_offset, row_dist
1367 INTEGER, INTENT(IN) :: myprow
1368 REAL(kind=dp), INTENT(IN) :: eps_filter
1369
1370 CHARACTER(LEN=*), PARAMETER :: routinen = 'add_Z_lP_columns'
1371
1372 INTEGER :: current_chunk_size, g_pt, handle, i_blk, &
1373 loc_ptr, ncolumn, r_end, r_start
1374 LOGICAL :: row_owned
1375 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: z_blk
1376
1377 CALL timeset(routinen, handle)
1378
1379 ncolumn = SIZE(z_block, 2)
1380 cpassert(first_column > 0)
1381 cpassert(first_column + ncolumn - 1 <= atom_block_size)
1382 ALLOCATE (z_blk(maxval(r_blk_sizes), atom_block_size), source=0.0_dp)
1383 loc_ptr = 1
1384 DO i_blk = 1, SIZE(r_blk_sizes)
1385 r_start = row_offset(i_blk) + 1
1386 r_end = row_offset(i_blk) + r_blk_sizes(i_blk)
1387 current_chunk_size = r_blk_sizes(i_blk)
1388 row_owned = row_dist(i_blk) == myprow
1389 z_blk = 0.0_dp
1390 DO WHILE (loc_ptr <= n_local_grid)
1391 g_pt = local_grid_idx(loc_ptr)
1392 IF (g_pt > r_end) EXIT
1393 IF (row_owned) THEN
1394 z_blk(g_pt - r_start + 1, first_column:first_column + ncolumn - 1) = &
1395 z_block(loc_ptr, 1:ncolumn)
1396 END IF
1397 loc_ptr = loc_ptr + 1
1398 END DO
1399 IF (row_owned .AND. maxval(abs(z_blk(1:current_chunk_size, :))) > eps_filter) THEN
1400 CALL dbcsr_put_block(mat_z_lp, row=i_blk, col=atom_index, &
1401 block=z_blk(1:current_chunk_size, :), summation=.true.)
1402 END IF
1403 END DO
1404 DEALLOCATE (z_blk)
1405
1406 CALL timestop(handle)
1407
1408 END SUBROUTINE add_z_lp_columns
1409
1410! **************************************************************************************************
1411!> \brief Computes m_l^A = OR_{μ∈A}[ϕ_μ(r_l) /= 0]. The product
1412!>
1413!> ϕ_μ(r_l) ϕ_ν(r_l), μ∈A, ν∈B,
1414!>
1415!> is evaluated only where m_l^A AND m_l^B is true. This avoids products and contractions
1416!> whenever either atom has no nonzero AO on r_l; no additional numerical threshold is used.
1417!> \param bs_env ...
1418!> \param phi_val ...
1419!> \param ao_col_map ...
1420!> \param nonzero_ao ...
1421! **************************************************************************************************
1422 SUBROUTINE compute_nonzero_ao_grid_mask(bs_env, phi_val, ao_col_map, nonzero_ao)
1423 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1424 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: phi_val
1425 INTEGER, DIMENSION(:), INTENT(IN) :: ao_col_map
1426 LOGICAL, ALLOCATABLE, DIMENSION(:, :), INTENT(OUT) :: nonzero_ao
1427
1428 CHARACTER(LEN=*), PARAMETER :: routinen = 'compute_nonzero_AO_grid_mask'
1429
1430 INTEGER :: col, first, handle, iatom, last, natom, &
1431 ngrid, point
1432
1433 CALL timeset(routinen, handle)
1434
1435 ngrid = SIZE(phi_val, 1)
1436 natom = bs_env%n_atom
1437 ALLOCATE (nonzero_ao(ngrid, natom), source=.false.)
1438 !$OMP PARALLEL DO DEFAULT(NONE) SCHEDULE(STATIC) &
1439 !$OMP SHARED(bs_env, phi_val, ao_col_map, nonzero_ao, ngrid, natom) &
1440 !$OMP PRIVATE(iatom, first, last, col, point)
1441 DO iatom = 1, natom
1442 first = ao_col_map(bs_env%i_ao_start_from_atom(iatom))
1443 IF (first == 0) cycle
1444 last = ao_col_map(bs_env%i_ao_end_from_atom(iatom))
1445 DO col = first, last
1446 DO point = 1, ngrid
1447 nonzero_ao(point, iatom) = &
1448 nonzero_ao(point, iatom) .OR. phi_val(point, col) /= 0.0_dp
1449 END DO
1450 END DO
1451 END DO
1452 !$OMP END PARALLEL DO
1453
1454 CALL timestop(handle)
1455 END SUBROUTINE compute_nonzero_ao_grid_mask
1456
1457! **************************************************************************************************
1458!> \brief Computes d_lp = Σ_{μνP} ϕ_μ(r_l)ϕ_ν(r_l)(μν|P)U_Pp for all optimized
1459!> columns p that contain reference RI functions P on atom I.
1460!> \param bs_env ...
1461!> \param ctx ...
1462!> \param phi_val ...
1463!> \param ao_col_map ...
1464!> \param d_lp ...
1465!> \param n_grid ...
1466!> \param iatom ...
1467!> \param U_Pp ...
1468!> \param max_ao_size ...
1469! **************************************************************************************************
1470 SUBROUTINE compute_d_lp_auto_ri_atom(bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid, iatom, &
1471 U_Pp, max_ao_size)
1472!$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
1473 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1474 TYPE(gw_3c_ctx_type), INTENT(IN) :: ctx
1475 REAL(kind=dp), CONTIGUOUS, DIMENSION(:, :), &
1476 INTENT(IN) :: phi_val
1477 INTEGER, DIMENSION(:), INTENT(IN) :: ao_col_map
1478 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: d_lp
1479 INTEGER, INTENT(IN) :: n_grid, iatom
1480 REAL(kind=dp), CONTIGUOUS, DIMENSION(:, :), &
1481 INTENT(IN) :: u_pp
1482 INTEGER, INTENT(IN) :: max_ao_size
1483
1484 CHARACTER(LEN=*), PARAMETER :: routinen = 'compute_d_lp_auto_ri_atom'
1485 INTEGER, PARAMETER :: grid_chunk = 1024
1486
1487 INTEGER :: jatom, katom, c, handle, i_thread, j, jk_idx, jsize, jstart, k, ksize, &
1488 kstart, l, l0, ncol, nri_ref, nthreads, ri, thread_id
1489 LOGICAL :: screened
1490 REAL(kind=dp) :: pair_factor
1491 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: int_2d_prv, rho_chunk
1492 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :) :: d_lp_threads, int_3c_prv
1493 TYPE(gw_3c_ws_type) :: ws
1494
1495 LOGICAL, ALLOCATABLE, DIMENSION(:, :) :: nonzero_ao
1496 INTEGER, ALLOCATABLE, DIMENSION(:) :: grid_index
1497 INTEGER :: n_grid_pair, grid_l, point
1498 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: grid_result
1499
1500 CALL timeset(routinen, handle)
1501 ncol = SIZE(u_pp, 2)
1502 nri_ref = get_ref_ri_size(bs_env, iatom)
1503 nthreads = 1
1504!$ nthreads = omp_get_max_threads()
1505 cpassert(SIZE(d_lp, 1) == n_grid)
1506 cpassert(SIZE(d_lp, 2) == ncol)
1507 cpassert(SIZE(u_pp, 1) == nri_ref)
1508 ALLOCATE (d_lp_threads(n_grid, ncol, nthreads), source=0.0_dp)
1509
1510 CALL compute_nonzero_ao_grid_mask(bs_env, phi_val, ao_col_map, nonzero_ao)
1511
1512 !$OMP PARALLEL DEFAULT(NONE) &
1513 !$OMP SHARED(nonzero_ao, bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid, iatom, &
1514 !$OMP U_Pp, &
1515 !$OMP max_ao_size, ncol, nRI_ref, d_lp_threads, nthreads) &
1516 !$OMP PRIVATE(grid_index, n_grid_pair, grid_l, point, grid_result, &
1517 !$OMP jatom, katom, c, &
1518 !$OMP i_thread, j, jk_idx, jsize, jstart, k, ksize, &
1519 !$OMP kstart, l, l0, ri, screened, pair_factor, int_2d_prv, rho_chunk, &
1520 !$OMP int_3c_prv, ws, thread_id)
1521
1522 thread_id = 1
1523!$ thread_id = omp_get_thread_num() + 1
1524
1525 CALL gw_3c_ws_create(ws, ctx)
1526 ALLOCATE (int_3c_prv(max_ao_size, max_ao_size, ncol))
1527 ALLOCATE (int_2d_prv(max_ao_size*max_ao_size, ncol))
1528 ALLOCATE (rho_chunk(grid_chunk, max_ao_size*max_ao_size))
1529 ALLOCATE (grid_index(n_grid), grid_result(grid_chunk, ncol))
1530
1531 !$OMP DO SCHEDULE(DYNAMIC)
1532 DO jatom = 1, bs_env%n_atom
1533 DO katom = jatom, bs_env%n_atom
1534 jstart = ao_col_map(bs_env%i_ao_start_from_atom(jatom))
1535 kstart = ao_col_map(bs_env%i_ao_start_from_atom(katom))
1536 IF (jstart == 0 .OR. kstart == 0) cycle
1537 jsize = bs_env%i_ao_end_from_atom(jatom) - bs_env%i_ao_start_from_atom(jatom) + 1
1538 ksize = bs_env%i_ao_end_from_atom(katom) - bs_env%i_ao_start_from_atom(katom) + 1
1539 n_grid_pair = 0
1540 DO grid_l = 1, n_grid
1541 IF (.NOT. (nonzero_ao(grid_l, jatom) .AND. nonzero_ao(grid_l, katom))) cycle
1542 n_grid_pair = n_grid_pair + 1
1543 grid_index(n_grid_pair) = grid_l
1544 END DO
1545 IF (n_grid_pair == 0) cycle
1546 int_3c_prv(1:jsize, 1:ksize, 1:ncol) = 0.0_dp
1547 CALL build_3c_integral_block_auto_ri_ctx( &
1548 int_3c_prv(1:jsize, 1:ksize, 1:ncol), ctx, ws, &
1549 atom_j=jatom, atom_k=katom, atom_i=iatom, &
1550 transform=u_pp, transform_row=1, screened=screened)
1551 IF (screened) cycle
1552 DO ri = 1, ncol
1553 DO k = 1, ksize
1554 DO j = 1, jsize
1555 jk_idx = (k - 1)*jsize + j
1556 int_2d_prv(jk_idx, ri) = int_3c_prv(j, k, ri)
1557 END DO
1558 END DO
1559 END DO
1560 pair_factor = 1.0_dp
1561 IF (jatom /= katom) pair_factor = 2.0_dp
1562 DO l0 = 1, n_grid_pair, grid_chunk
1563 c = min(grid_chunk, n_grid_pair - l0 + 1)
1564 DO k = 1, ksize
1565 DO j = 1, jsize
1566 jk_idx = (k - 1)*jsize + j
1567 DO l = 1, c
1568 point = grid_index(l0 + l - 1)
1569 rho_chunk(l, jk_idx) = phi_val(point, jstart + j - 1)* &
1570 phi_val(point, kstart + k - 1)
1571 END DO
1572 END DO
1573 END DO
1574 CALL dgemm('N', 'N', c, ncol, jsize*ksize, pair_factor, rho_chunk, grid_chunk, &
1575 int_2d_prv, max_ao_size*max_ao_size, 0.0_dp, &
1576 grid_result, grid_chunk)
1577 DO ri = 1, ncol
1578 DO l = 1, c
1579 point = grid_index(l0 + l - 1)
1580 d_lp_threads(point, ri, thread_id) = &
1581 d_lp_threads(point, ri, thread_id) + grid_result(l, ri)
1582 END DO
1583 END DO
1584 END DO
1585 END DO
1586 END DO
1587 !$OMP END DO
1588
1589 !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
1590 DO ri = 1, ncol
1591 DO l = 1, n_grid
1592 DO i_thread = 1, nthreads
1593 d_lp(l, ri) = d_lp(l, ri) + d_lp_threads(l, ri, i_thread)
1594 END DO
1595 END DO
1596 END DO
1597 !$OMP END DO
1598 DEALLOCATE (int_3c_prv, int_2d_prv, rho_chunk)
1599 DEALLOCATE (grid_index, grid_result)
1600 CALL gw_3c_ws_release(ws)
1601 !$OMP END PARALLEL
1602
1603 DEALLOCATE (d_lp_threads)
1604
1605 DEALLOCATE (nonzero_ao)
1606
1607 CALL timestop(handle)
1608
1609 END SUBROUTINE compute_d_lp_auto_ri_atom
1610
1611! **************************************************************************************************
1612!> \brief Computes d_lp = Σ_{μνP} ϕ_μ(r_l)ϕ_ν(r_l)(μν|P)U_Pp for all AA and AB
1613!> columns p of one RI-RS matrix block. P can belong to either atom of an AB contraction.
1614!> \param bs_env ...
1615!> \param ctx ...
1616!> \param phi_val ...
1617!> \param ao_col_map ...
1618!> \param d_lp ...
1619!> \param n_grid ...
1620!> \param ri_coefficients ...
1621!> \param active_atom ...
1622!> \param max_ao_size ...
1623!> \param atom_j_mepos ...
1624!> \param atom_j_stride ...
1625! **************************************************************************************************
1626 SUBROUTINE compute_d_lp_auto_ri_atoms(bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid, &
1627 ri_coefficients, active_atom, max_ao_size, atom_j_mepos, &
1628 atom_j_stride)
1629!$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num
1630 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1631 TYPE(gw_3c_ctx_type), INTENT(IN) :: ctx
1632 REAL(kind=dp), CONTIGUOUS, DIMENSION(:, :), &
1633 INTENT(IN) :: phi_val
1634 INTEGER, DIMENSION(:), INTENT(IN) :: ao_col_map
1635 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: d_lp
1636 INTEGER, INTENT(IN) :: n_grid
1637 REAL(kind=dp), DIMENSION(:, :, :), INTENT(IN) :: ri_coefficients
1638 LOGICAL, DIMENSION(:), INTENT(IN) :: active_atom
1639 INTEGER, INTENT(IN) :: max_ao_size, atom_j_mepos, atom_j_stride
1640
1641 CHARACTER(LEN=*), PARAMETER :: routinen = 'compute_d_lp_auto_ri_atoms'
1642 INTEGER, PARAMETER :: grid_chunk = 1024
1643
1644 INTEGER :: active_column, iatom, jatom, katom, c, handle, i_thread, j, jk_idx, jsize, &
1645 jstart, k, ksize, kstart, l, l0, &
1646 max_active, nactive, ncol, nri_ref, nthreads, ri, thread_id
1647 INTEGER, ALLOCATABLE, DIMENSION(:) :: atom_ncol
1648 INTEGER, ALLOCATABLE, DIMENSION(:, :) :: atom_column
1649 LOGICAL :: any_integral, screened
1650 REAL(kind=dp) :: pair_factor
1651 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: int_2d_prv, rho_chunk
1652 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :) :: coefficient_compact, d_lp_threads, &
1653 int_3c_prv, int_3c_atom
1654 TYPE(gw_3c_ws_type) :: ws
1655
1656 LOGICAL, ALLOCATABLE, DIMENSION(:, :) :: nonzero_ao
1657 INTEGER, ALLOCATABLE, DIMENSION(:) :: grid_index
1658 INTEGER :: n_grid_pair, grid_l, point
1659 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: grid_result
1660
1661 CALL timeset(routinen, handle)
1662 ncol = SIZE(d_lp, 2)
1663 nthreads = 1
1664!$ nthreads = omp_get_max_threads()
1665 cpassert(SIZE(d_lp, 1) == n_grid)
1666 cpassert(SIZE(ri_coefficients, 2) == ncol)
1667 cpassert(SIZE(ri_coefficients, 3) == SIZE(active_atom))
1668 ALLOCATE (atom_ncol(SIZE(active_atom)), atom_column(ncol, SIZE(active_atom)))
1669 atom_ncol = 0
1670 atom_column = 0
1671 DO iatom = 1, SIZE(active_atom)
1672 IF (.NOT. active_atom(iatom)) cycle
1673 nri_ref = get_ref_ri_size(bs_env, iatom)
1674 DO ri = 1, ncol
1675 IF (.NOT. any(ri_coefficients(1:nri_ref, ri, iatom) /= 0.0_dp)) cycle
1676 atom_ncol(iatom) = atom_ncol(iatom) + 1
1677 atom_column(atom_ncol(iatom), iatom) = ri
1678 END DO
1679 END DO
1680 max_active = maxval(atom_ncol)
1681 cpassert(max_active > 0)
1682 ALLOCATE (coefficient_compact(SIZE(ri_coefficients, 1), max_active, &
1683 SIZE(active_atom)), source=0.0_dp)
1684 DO iatom = 1, SIZE(active_atom)
1685 nri_ref = get_ref_ri_size(bs_env, iatom)
1686 DO active_column = 1, atom_ncol(iatom)
1687 ri = atom_column(active_column, iatom)
1688 coefficient_compact(1:nri_ref, active_column, iatom) = &
1689 ri_coefficients(1:nri_ref, ri, iatom)
1690 END DO
1691 END DO
1692 ALLOCATE (d_lp_threads(n_grid, ncol, nthreads), source=0.0_dp)
1693
1694 CALL compute_nonzero_ao_grid_mask(bs_env, phi_val, ao_col_map, nonzero_ao)
1695
1696 !$OMP PARALLEL DEFAULT(NONE) &
1697 !$OMP SHARED(nonzero_ao, bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid, ri_coefficients, &
1698 !$OMP active_atom, max_ao_size, atom_j_mepos, atom_j_stride, ncol, &
1699 !$OMP d_lp_threads, nthreads, atom_ncol, &
1700 !$OMP atom_column, coefficient_compact, max_active) &
1701 !$OMP PRIVATE(grid_index, n_grid_pair, grid_l, point, grid_result, &
1702 !$OMP active_column, iatom, jatom, katom, c, i_thread, j, jk_idx, jsize, jstart, &
1703 !$OMP k, ksize, kstart, l, l0, &
1704 !$OMP nactive, nRI_ref, ri, any_integral, screened, pair_factor, &
1705 !$OMP int_2d_prv, rho_chunk, &
1706 !$OMP int_3c_prv, int_3c_atom, ws, thread_id)
1707
1708 thread_id = 1
1709!$ thread_id = omp_get_thread_num() + 1
1710
1711 CALL gw_3c_ws_create(ws, ctx)
1712 ALLOCATE (int_3c_prv(max_ao_size, max_ao_size, ncol))
1713 ALLOCATE (int_3c_atom(max_ao_size, max_ao_size, max_active))
1714 ALLOCATE (int_2d_prv(max_ao_size*max_ao_size, ncol))
1715 ALLOCATE (rho_chunk(grid_chunk, max_ao_size*max_ao_size))
1716 ALLOCATE (grid_index(n_grid), grid_result(grid_chunk, ncol))
1717
1718 !$OMP DO SCHEDULE(DYNAMIC)
1719 DO jatom = atom_j_mepos + 1, bs_env%n_atom, atom_j_stride
1720 DO katom = jatom, bs_env%n_atom
1721 jstart = ao_col_map(bs_env%i_ao_start_from_atom(jatom))
1722 kstart = ao_col_map(bs_env%i_ao_start_from_atom(katom))
1723 IF (jstart == 0 .OR. kstart == 0) cycle
1724 jsize = bs_env%i_ao_end_from_atom(jatom) - bs_env%i_ao_start_from_atom(jatom) + 1
1725 ksize = bs_env%i_ao_end_from_atom(katom) - bs_env%i_ao_start_from_atom(katom) + 1
1726 n_grid_pair = 0
1727 DO grid_l = 1, n_grid
1728 IF (.NOT. (nonzero_ao(grid_l, jatom) .AND. nonzero_ao(grid_l, katom))) cycle
1729 n_grid_pair = n_grid_pair + 1
1730 grid_index(n_grid_pair) = grid_l
1731 END DO
1732 IF (n_grid_pair == 0) cycle
1733 int_3c_prv(1:jsize, 1:ksize, 1:ncol) = 0.0_dp
1734 any_integral = .false.
1735 DO iatom = 1, SIZE(active_atom)
1736 IF (.NOT. active_atom(iatom)) cycle
1737 nri_ref = get_ref_ri_size(bs_env, iatom)
1738 nactive = atom_ncol(iatom)
1739 int_3c_atom(1:jsize, 1:ksize, 1:nactive) = 0.0_dp
1740 CALL build_3c_integral_block_auto_ri_ctx( &
1741 int_3c_atom(1:jsize, 1:ksize, 1:nactive), ctx, ws, &
1742 atom_j=jatom, atom_k=katom, atom_i=iatom, &
1743 transform=coefficient_compact(1:nri_ref, 1:nactive, iatom), &
1744 transform_row=1, screened=screened)
1745 IF (.NOT. screened) THEN
1746 any_integral = .true.
1747 DO active_column = 1, nactive
1748 ri = atom_column(active_column, iatom)
1749 int_3c_prv(1:jsize, 1:ksize, ri) = &
1750 int_3c_prv(1:jsize, 1:ksize, ri) + &
1751 int_3c_atom(1:jsize, 1:ksize, active_column)
1752 END DO
1753 END IF
1754 END DO
1755 IF (.NOT. any_integral) cycle
1756
1757 DO ri = 1, ncol
1758 DO k = 1, ksize
1759 DO j = 1, jsize
1760 jk_idx = (k - 1)*jsize + j
1761 int_2d_prv(jk_idx, ri) = int_3c_prv(j, k, ri)
1762 END DO
1763 END DO
1764 END DO
1765
1766 pair_factor = 1.0_dp
1767 IF (jatom /= katom) pair_factor = 2.0_dp
1768 DO l0 = 1, n_grid_pair, grid_chunk
1769 c = min(grid_chunk, n_grid_pair - l0 + 1)
1770 DO k = 1, ksize
1771 DO j = 1, jsize
1772 jk_idx = (k - 1)*jsize + j
1773 DO l = 1, c
1774 point = grid_index(l0 + l - 1)
1775 rho_chunk(l, jk_idx) = phi_val(point, jstart + j - 1)* &
1776 phi_val(point, kstart + k - 1)
1777 END DO
1778 END DO
1779 END DO
1780 CALL dgemm('N', 'N', c, ncol, jsize*ksize, pair_factor, rho_chunk, grid_chunk, &
1781 int_2d_prv, max_ao_size*max_ao_size, 0.0_dp, &
1782 grid_result, grid_chunk)
1783 DO ri = 1, ncol
1784 DO l = 1, c
1785 point = grid_index(l0 + l - 1)
1786 d_lp_threads(point, ri, thread_id) = &
1787 d_lp_threads(point, ri, thread_id) + grid_result(l, ri)
1788 END DO
1789 END DO
1790 END DO
1791 END DO
1792 END DO
1793 !$OMP END DO
1794
1795 !$OMP DO COLLAPSE(2) SCHEDULE(STATIC)
1796 DO ri = 1, ncol
1797 DO l = 1, n_grid
1798 DO i_thread = 1, nthreads
1799 d_lp(l, ri) = d_lp(l, ri) + d_lp_threads(l, ri, i_thread)
1800 END DO
1801 END DO
1802 END DO
1803 !$OMP END DO
1804 DEALLOCATE (int_3c_prv, int_3c_atom, int_2d_prv, rho_chunk)
1805 DEALLOCATE (grid_index, grid_result)
1806 CALL gw_3c_ws_release(ws)
1807 !$OMP END PARALLEL
1808
1809 DEALLOCATE (coefficient_compact, d_lp_threads, atom_column, atom_ncol)
1810
1811 DEALLOCATE (nonzero_ao)
1812
1813 CALL timestop(handle)
1814
1815 END SUBROUTINE compute_d_lp_auto_ri_atoms
1816
1817! **************************************************************************************************
1818!> \brief Computes d_lp = Σ_A Σ_{P∈A} d_lP U_Pp in rank-sized batches on a common grid.
1819!> \param bs_env ...
1820!> \param ctx ...
1821!> \param phi_val ...
1822!> \param ao_col_map ...
1823!> \param d_lp ...
1824!> \param n_grid ...
1825!> \param max_ao_size ...
1826!> \param mepos ...
1827!> \param num_pe ...
1828! **************************************************************************************************
1829 SUBROUTINE compute_d_lp_auto_ri_batch(bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid, &
1830 max_ao_size, mepos, num_pe)
1831 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1832 TYPE(gw_3c_ctx_type), INTENT(IN) :: ctx
1833 REAL(kind=dp), CONTIGUOUS, DIMENSION(:, :), &
1834 INTENT(IN) :: phi_val
1835 INTEGER, DIMENSION(:), INTENT(IN) :: ao_col_map
1836 REAL(kind=dp), DIMENSION(:, :), INTENT(INOUT) :: d_lp
1837 INTEGER, INTENT(IN) :: n_grid, max_ao_size, mepos, num_pe
1838
1839 CHARACTER(LEN=*), PARAMETER :: routinen = 'compute_d_lp_auto_ri_batch'
1840
1841 INTEGER :: column, handle, iatom, n_done, n_total, &
1842 ncol_batch
1843 INTEGER, ALLOCATABLE, DIMENSION(:) :: global_map
1844 REAL(kind=dp) :: item_start_time
1845 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: d_lp_batch, u_pp
1846
1847 CALL timeset(routinen, handle)
1848
1849 n_total = 0
1850 DO iatom = mepos + 1, bs_env%n_atom, num_pe
1851 n_total = n_total + 1
1852 END DO
1853 n_done = 0
1854
1855 DO iatom = mepos + 1, bs_env%n_atom, num_pe
1856 item_start_time = m_walltime()
1857 CALL collect_auto_ri_columns_for_atom(bs_env, iatom, u_pp, global_map)
1858 ncol_batch = SIZE(global_map)
1859 IF (ncol_batch == 0) THEN
1860 DEALLOCATE (u_pp, global_map)
1861 n_done = n_done + 1
1862 CALL print_z_lp_progress(bs_env, n_done, n_total, &
1863 m_walltime() - item_start_time)
1864 cycle
1865 END IF
1866
1867 ALLOCATE (d_lp_batch(n_grid, ncol_batch), source=0.0_dp)
1868 CALL compute_d_lp_auto_ri_atom(bs_env, ctx, phi_val, ao_col_map, d_lp_batch, &
1869 n_grid, iatom, u_pp, max_ao_size)
1870 DO column = 1, ncol_batch
1871 d_lp(:, global_map(column)) = d_lp(:, global_map(column)) + d_lp_batch(:, column)
1872 END DO
1873 DEALLOCATE (u_pp, global_map, d_lp_batch)
1874 n_done = n_done + 1
1875 CALL print_z_lp_progress(bs_env, n_done, n_total, &
1876 m_walltime() - item_start_time)
1877 END DO
1878 CALL timestop(handle)
1879
1880 END SUBROUTINE compute_d_lp_auto_ri_batch
1881
1882! **************************************************************************************************
1883!> \brief Collects every optimized column p containing reference functions P on atom A. It returns
1884!>
1885!> U_Pp^A
1886!>
1887!> together with the global optimized-column index of q.
1888!> \param bs_env ...
1889!> \param iatom ...
1890!> \param U_Pp ...
1891!> \param global_map ...
1892! **************************************************************************************************
1893 SUBROUTINE collect_auto_ri_columns_for_atom(bs_env, iatom, U_Pp, global_map)
1894 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1895 INTEGER, INTENT(IN) :: iatom
1896 REAL(kind=dp), ALLOCATABLE, INTENT(OUT) :: u_pp(:, :)
1897 INTEGER, ALLOCATABLE, INTENT(OUT) :: global_map(:)
1898
1899 CHARACTER(LEN=*), PARAMETER :: routinen = 'collect_auto_ri_columns_for_atom'
1900
1901 INTEGER :: ab_block, atom_a, atom_b, column, global_column, handle, local_column, ncol, &
1902 ncol_batch, nri_ref, nri_ref_a, output_offset, row_first
1903 REAL(kind=dp), ALLOCATABLE :: u_pp_ab(:, :)
1904
1905 CALL timeset(routinen, handle)
1906
1907 ncol_batch = 0
1908 DO ab_block = 1, bs_env%auto_ri%AB_block_count
1909 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1910 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1911 IF (iatom == atom_a .OR. iatom == atom_b) THEN
1912 ncol_batch = ncol_batch + bs_env%auto_ri%AB_size_opt_RI(ab_block)
1913 END IF
1914 END DO
1915
1916 nri_ref = get_ref_ri_size(bs_env, iatom)
1917 ALLOCATE (u_pp(nri_ref, ncol_batch), source=0.0_dp)
1918 ALLOCATE (global_map(ncol_batch))
1919 column = 0
1920 DO ab_block = 1, bs_env%auto_ri%AB_block_count
1921 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1922 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1923 IF (iatom /= atom_a .AND. iatom /= atom_b) cycle
1924 ncol = bs_env%auto_ri%AB_size_opt_RI(ab_block)
1925 CALL get_u_pp_ab(bs_env%auto_ri, ab_block, u_pp_ab)
1926 row_first = 1
1927 IF (iatom == atom_b .AND. atom_b /= atom_a) THEN
1928 nri_ref_a = get_ref_ri_size(bs_env, atom_a)
1929 row_first = 1 + nri_ref_a
1930 END IF
1931 u_pp(:, column + 1:column + ncol) = &
1932 u_pp_ab( &
1933 row_first:row_first + nri_ref - 1, 1:ncol)
1934
1935 DO local_column = 1, ncol
1936 IF (local_column <= bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)) THEN
1937 output_offset = sum(bs_env%auto_ri%sizes_opt_RI(:atom_a - 1)) + &
1938 bs_env%auto_ri%AB_first_p_A(ab_block) - 1
1939 global_column = output_offset + local_column
1940 ELSE
1941 cpassert(atom_b /= atom_a)
1942 output_offset = sum(bs_env%auto_ri%sizes_opt_RI(:atom_b - 1)) + &
1943 bs_env%auto_ri%AB_first_p_B(ab_block) - 1
1944 global_column = output_offset + local_column - &
1945 bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
1946 END IF
1947 global_map(column + local_column) = global_column
1948 END DO
1949 column = column + ncol
1950 DEALLOCATE (u_pp_ab)
1951 END DO
1952 cpassert(column == ncol_batch)
1953
1954 CALL timestop(handle)
1955
1956 END SUBROUTINE collect_auto_ri_columns_for_atom
1957
1958! **************************************************************************************************
1959!> \brief Unpacks one AB contraction matrix U_Pp; B=A denotes an AA block.
1960!> \param auto_ri ...
1961!> \param AB_block ...
1962!> \param U_Pp ...
1963! **************************************************************************************************
1964 SUBROUTINE get_u_pp_ab(auto_ri, AB_block, U_Pp)
1965 TYPE(auto_ri_type), INTENT(IN) :: auto_ri
1966 INTEGER, INTENT(IN) :: ab_block
1967 REAL(kind=dp), ALLOCATABLE, INTENT(OUT) :: u_pp(:, :)
1968
1969 INTEGER :: first, last, ncolumn, nrow
1970
1971 nrow = auto_ri%AB_size_ref_RI(ab_block)
1972 ncolumn = auto_ri%AB_size_opt_RI(ab_block)
1973 first = auto_ri%U_Pp_AB_offset(ab_block)
1974 last = first + nrow*ncolumn - 1
1975 ALLOCATE (u_pp(nrow, ncolumn))
1976 u_pp(:, :) = reshape(auto_ri%U_Pp_AB(first:last), [nrow, ncolumn])
1977
1978 END SUBROUTINE get_u_pp_ab
1979
1980! **************************************************************************************************
1981!> \brief Computes the fitting radius for every optimized atomic column block. If q assigned to A
1982!> contains reference functions on B, the required radius is
1983!>
1984!> R_A^fit = max_B [r_c + R_B^RI + |R_A - R_B|].
1985!> \param bs_env ...
1986!> \param radius ...
1987! **************************************************************************************************
1988 SUBROUTINE compute_auto_ri_grid_radii(bs_env, radius)
1989 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
1990 REAL(kind=dp), INTENT(OUT) :: radius(:)
1991
1992 CHARACTER(LEN=*), PARAMETER :: routinen = 'compute_auto_ri_grid_radii'
1993
1994 INTEGER :: a, ab_block, b, handle, n_to_a, ncol
1995 REAL(kind=dp) :: cutoff, distance
1996 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1997
1998 CALL timeset(routinen, handle)
1999
2000 particle_set => bs_env%ri_rs%particle_set
2001 radius = bs_env%ri_rs%cutoff_radius_ri_rs
2002 IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp) THEN
2003 CALL timestop(handle)
2004 RETURN
2005 END IF
2006 radius = 0.0_dp
2007 cutoff = bs_env%ri_metric%cutoff_radius
2008 DO ab_block = 1, bs_env%auto_ri%AB_block_count
2009 a = bs_env%auto_ri%AB_atom_A(ab_block)
2010 b = bs_env%auto_ri%AB_atom_B(ab_block)
2011 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
2012 ncol = bs_env%auto_ri%AB_size_opt_RI(ab_block)
2013 IF (n_to_a > 0) THEN
2014 radius(a) = max(radius(a), cutoff + bs_env%ri_rs%radius_ri_per_atom(a))
2015 IF (b /= a) THEN
2016 distance = norm2(particle_set(a)%r - particle_set(b)%r)
2017 radius(a) = max(radius(a), cutoff + bs_env%ri_rs%radius_ri_per_atom(b) + distance)
2018 END IF
2019 END IF
2020 IF (n_to_a < ncol) THEN
2021 cpassert(b /= a)
2022 distance = norm2(particle_set(b)%r - particle_set(a)%r)
2023 radius(b) = max(radius(b), cutoff + bs_env%ri_rs%radius_ri_per_atom(b), &
2024 cutoff + bs_env%ri_rs%radius_ri_per_atom(a) + distance)
2025 END IF
2026 END DO
2027
2028 CALL timestop(handle)
2029 END SUBROUTINE compute_auto_ri_grid_radii
2030
2031! **************************************************************************************************
2032!> \brief Computes
2033!>
2034!> d_lp = Σ_A Σ_{P∈A} d_lP U_Pp^A,
2035!> d_lP = Σ_μν ϕ_μ(r_l) ϕ_ν(r_l) (μν|P),
2036!>
2037!> on the union of the atomic RI-RS grids needed by q. Each atom's three-center integrals are
2038!> evaluated once and transformed with U_Pp^A.
2039!> \param qs_env ...
2040!> \param bs_env ...
2041!> \param ctx ...
2042!> \param grid ...
2043!> \param mat_phi ...
2044!> \param mat_rhs ...
2045!> \param max_ao_size ...
2046! **************************************************************************************************
2047 SUBROUTINE compute_auto_ri_d_lp(qs_env, bs_env, ctx, grid, mat_phi, mat_rhs, max_ao_size)
2048 TYPE(qs_environment_type), POINTER :: qs_env
2049 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2050 TYPE(gw_3c_ctx_type), INTENT(IN) :: ctx
2051 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: grid
2052 TYPE(dbcsr_type), INTENT(IN) :: mat_phi
2053 TYPE(dbcsr_type), INTENT(OUT) :: mat_rhs
2054 INTEGER, INTENT(IN) :: max_ao_size
2055
2056 CHARACTER(LEN=*), PARAMETER :: routinen = 'compute_auto_ri_d_lp'
2057
2058 INTEGER :: ab_block, atom_a, atom_b, first, fit_atom, handle, handle_project, handle_rhs, l, &
2059 last, n_done, n_first_p_abs, n_to_a, n_total, n_union, nao, natom, ncol, ngrid, npcol, &
2060 nprow, ri_atom
2061 INTEGER, ALLOCATABLE, DIMENSION(:) :: ao_map, global_map, local_index, &
2062 row_offset, union_index
2063 INTEGER, DIMENSION(:), POINTER :: ab_row_dist, col_dist, &
2064 first_p_abs_per_atom, retained_size, &
2065 row_dist, row_size
2066 LOGICAL, ALLOCATABLE, DIMENSION(:) :: needed_fit_atom, union_mask
2067 REAL(kind=dp) :: item_start_time, radius
2068 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: fit_radius
2069 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: column_map, phi, rhs, u_pp, union_grid
2070 TYPE(cell_type), POINTER :: cell
2071 TYPE(dbcsr_distribution_type) :: dist_ab, dist_phi, dist_t
2072 TYPE(dbcsr_type) :: ab_d_lp, transform
2073 TYPE(mp_para_env_type), POINTER :: para_env
2074 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2075 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
2076
2077 CALL timeset(routinen, handle)
2078 CALL get_qs_env(qs_env, para_env=para_env, particle_set=particle_set, &
2079 qs_kind_set=qs_kind_set, cell=cell)
2080 natom = bs_env%n_atom
2081 CALL dbcsr_get_info(mat_phi, row_blk_size=row_size, distribution=dist_phi)
2082 CALL dbcsr_distribution_get(dist_phi, row_dist=row_dist, nprows=nprow, npcols=npcol)
2083 ALLOCATE (first_p_abs_per_atom(natom), col_dist(natom), ab_row_dist(natom), &
2084 retained_size(natom), row_offset(SIZE(row_size)))
2085 retained_size(:) = bs_env%auto_ri%sizes_opt_RI
2086 DO ri_atom = 1, natom
2087 first_p_abs_per_atom(ri_atom) = 0
2088 DO ab_block = 1, bs_env%auto_ri%AB_block_count
2089 IF (ri_atom == bs_env%auto_ri%AB_atom_A(ab_block) .OR. &
2090 ri_atom == bs_env%auto_ri%AB_atom_B(ab_block)) THEN
2091 first_p_abs_per_atom(ri_atom) = &
2092 first_p_abs_per_atom(ri_atom) + &
2093 bs_env%auto_ri%AB_size_opt_RI(ab_block)
2094 END IF
2095 END DO
2096 col_dist(ri_atom) = mod(ri_atom - 1, npcol)
2097 ab_row_dist(ri_atom) = mod(ri_atom - 1, nprow)
2098 END DO
2099 row_offset(1) = 0
2100 DO l = 2, SIZE(row_size)
2101 row_offset(l) = row_offset(l - 1) + row_size(l - 1)
2102 END DO
2103 CALL dbcsr_distribution_new(dist_ab, template=dist_phi, &
2104 row_dist=row_dist, col_dist=col_dist)
2105 CALL dbcsr_create(ab_d_lp, name='AUTO_RI AA/AB d_lp', dist=dist_ab, &
2106 matrix_type=dbcsr_type_no_symmetry, row_blk_size=row_size, &
2107 col_blk_size=first_p_abs_per_atom)
2108 CALL dbcsr_distribution_new(dist_t, template=dist_phi, &
2109 row_dist=ab_row_dist, col_dist=col_dist)
2110 CALL dbcsr_create(transform, name='AUTO_RI U_Pp', dist=dist_t, &
2111 matrix_type=dbcsr_type_no_symmetry, row_blk_size=first_p_abs_per_atom, &
2112 col_blk_size=retained_size)
2113 CALL dbcsr_create(mat_rhs, name='AUTO_RI optimized d_lp', dist=dist_ab, &
2114 matrix_type=dbcsr_type_no_symmetry, row_blk_size=row_size, &
2115 col_blk_size=retained_size)
2116 ALLOCATE (fit_radius(natom))
2117 CALL compute_auto_ri_grid_radii(bs_env, fit_radius)
2118 ALLOCATE (needed_fit_atom(natom), union_mask(SIZE(grid, 2)))
2119 n_total = 0
2120 DO ri_atom = para_env%mepos + 1, natom, para_env%num_pe
2121 n_total = n_total + 1
2122 END DO
2123 n_done = 0
2124 CALL timeset(routinen//'_AB_d_lp', handle_rhs)
2125 DO ri_atom = para_env%mepos + 1, natom, para_env%num_pe
2126 item_start_time = m_walltime()
2127 needed_fit_atom = .false.
2128 DO ab_block = 1, bs_env%auto_ri%AB_block_count
2129 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
2130 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
2131 IF (ri_atom /= atom_a .AND. ri_atom /= atom_b) cycle
2132 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
2133 IF (n_to_a > 0) needed_fit_atom(atom_a) = .true.
2134 IF (n_to_a < bs_env%auto_ri%AB_size_opt_RI(ab_block)) THEN
2135 needed_fit_atom(atom_b) = .true.
2136 END IF
2137 END DO
2138 IF (.NOT. any(needed_fit_atom)) THEN
2139 n_done = n_done + 1
2140 CALL print_z_lp_progress(bs_env, n_done, n_total, &
2141 m_walltime() - item_start_time)
2142 cycle
2143 END IF
2144 union_mask = .false.
2145 radius = 0.0_dp
2146 DO fit_atom = 1, natom
2147 IF (.NOT. needed_fit_atom(fit_atom)) cycle
2148 radius = max(radius, fit_radius(fit_atom) + &
2149 norm2(particle_set(fit_atom)%r - particle_set(ri_atom)%r))
2150 DO l = 1, SIZE(grid, 2)
2151 IF (norm2(grid(:, l) - particle_set(fit_atom)%r) <= &
2152 fit_radius(fit_atom)) union_mask(l) = .true.
2153 END DO
2154 END DO
2155 n_union = count(union_mask)
2156 ALLOCATE (union_index(n_union), union_grid(3, n_union))
2157 n_union = 0
2158 DO l = 1, SIZE(grid, 2)
2159 IF (.NOT. union_mask(l)) cycle
2160 n_union = n_union + 1
2161 union_index(n_union) = l
2162 union_grid(:, n_union) = grid(:, l)
2163 END DO
2164 CALL build_phi_on_sphere(bs_env, qs_kind_set, union_grid, ri_atom, &
2165 radius + 1.0_dp, bs_env%i_ao_end_from_atom(natom), local_index, &
2166 ngrid, phi, ao_map, nao)
2167 local_index(1:ngrid) = union_index(local_index(1:ngrid))
2168 n_first_p_abs = first_p_abs_per_atom(ri_atom)
2169 CALL collect_auto_ri_columns_for_atom(bs_env, ri_atom, u_pp, global_map)
2170 cpassert(SIZE(global_map) == n_first_p_abs)
2171 first = 1
2172 DO fit_atom = 1, natom
2173 ncol = retained_size(fit_atom)
2174 last = first + ncol - 1
2175 IF (any(global_map >= first .AND. global_map <= last)) THEN
2176 ALLOCATE (column_map(n_first_p_abs, ncol), source=0.0_dp)
2177 DO l = 1, n_first_p_abs
2178 IF (global_map(l) < first .OR. global_map(l) > last) cycle
2179 column_map(l, global_map(l) - first + 1) = 1.0_dp
2180 END DO
2181 CALL dbcsr_put_block(transform, ri_atom, fit_atom, column_map)
2182 DEALLOCATE (column_map)
2183 END IF
2184 first = last + 1
2185 END DO
2186 ALLOCATE (rhs(ngrid, n_first_p_abs), source=0.0_dp)
2187 CALL compute_d_lp_auto_ri_atom(bs_env, ctx, phi, ao_map, rhs, ngrid, &
2188 ri_atom, u_pp, max_ao_size)
2189 CALL store_z_lp_columns(ab_d_lp, rhs, local_index, ngrid, n_first_p_abs, ri_atom, &
2190 row_size, row_offset, 0.0_dp)
2191 DEALLOCATE (rhs, u_pp, global_map, phi, ao_map, local_index, &
2192 union_grid, union_index)
2193 n_done = n_done + 1
2194 CALL print_z_lp_progress(bs_env, n_done, n_total, &
2195 m_walltime() - item_start_time)
2196 END DO
2197 CALL dbcsr_finalize(transform)
2198 CALL dbcsr_finalize(ab_d_lp)
2199 CALL timestop(handle_rhs)
2200 CALL timeset(routinen//'_transform', handle_project)
2201 CALL dbcsr_multiply('N', 'N', 1.0_dp, ab_d_lp, transform, 0.0_dp, &
2202 mat_rhs, filter_eps=0.0_dp)
2203 CALL timestop(handle_project)
2204 CALL dbcsr_release(ab_d_lp)
2205 CALL dbcsr_release(transform)
2206 CALL dbcsr_distribution_release(dist_ab)
2207 CALL dbcsr_distribution_release(dist_t)
2208 DEALLOCATE (first_p_abs_per_atom, retained_size, col_dist, ab_row_dist, row_offset, &
2209 fit_radius, needed_fit_atom, union_mask)
2210 CALL timestop(handle)
2211 END SUBROUTINE compute_auto_ri_d_lp
2212
2213! **************************************************************************************************
2214!> \brief Extracts rhs(i,q) = d_{local_index(i),q} from one optimized atomic DBCSR column block.
2215!> \param mat_rhs ...
2216!> \param atom_index ...
2217!> \param local_index ...
2218!> \param row_offset ...
2219!> \param rhs ...
2220! **************************************************************************************************
2221 SUBROUTINE extract_atom_d_lp(mat_rhs, atom_index, local_index, row_offset, rhs)
2222 TYPE(dbcsr_type), INTENT(INOUT) :: mat_rhs
2223 INTEGER, INTENT(IN) :: atom_index
2224 INTEGER, DIMENSION(:), INTENT(IN) :: local_index, row_offset
2225 REAL(kind=dp), DIMENSION(:, :), INTENT(OUT) :: rhs
2226
2227 CHARACTER(LEN=*), PARAMETER :: routinen = 'extract_atom_d_lp'
2228
2229 INTEGER :: handle, l, next_row, row
2230 LOGICAL :: found
2231 REAL(kind=dp), DIMENSION(:, :), POINTER :: block
2232
2233 CALL timeset(routinen, handle)
2234
2235 rhs = 0.0_dp
2236 row = 0
2237 next_row = 1
2238 NULLIFY (block)
2239 DO l = 1, SIZE(rhs, 1)
2240 DO WHILE (next_row <= SIZE(row_offset))
2241 IF (row_offset(next_row) >= local_index(l)) EXIT
2242 row = next_row
2243 next_row = next_row + 1
2244 CALL dbcsr_get_block_p(mat_rhs, row, atom_index, block, found)
2245 IF (.NOT. found) NULLIFY (block)
2246 END DO
2247 IF (ASSOCIATED(block)) rhs(l, :) = block(local_index(l) - row_offset(row), :)
2248 END DO
2249
2250 CALL timestop(handle)
2251 END SUBROUTINE extract_atom_d_lp
2252
2253! **************************************************************************************************
2254!> \brief Solves Σ_l' D_ll' Z_l'q = d_lp for each optimized atomic column block. Small grids are
2255!> gathered within one process column and solved by a local Cholesky factorization.
2256!> \param qs_env ...
2257!> \param bs_env ...
2258!> \param grid ...
2259!> \param mat_rhs ...
2260!> \param mat_z ...
2261! **************************************************************************************************
2262 SUBROUTINE fit_auto_ri_z_lp(qs_env, bs_env, grid, mat_rhs, mat_z)
2263 TYPE(qs_environment_type), POINTER :: qs_env
2264 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2265 REAL(kind=dp), INTENT(IN) :: grid(:, :)
2266 TYPE(dbcsr_type), INTENT(INOUT) :: mat_rhs, mat_z
2267
2268 CHARACTER(LEN=*), PARAMETER :: routinen = 'fit_auto_ri_z_lp'
2269
2270 INTEGER :: atom_index, base, group_size, handle, &
2271 handle_gather, i, info, mypcol, n_big, &
2272 n_small, nao, natom, ncol, ngrid, &
2273 npcol, slot
2274 INTEGER, ALLOCATABLE :: all_index(:), ao_map(:), big_list(:), &
2275 grid_size(:), local_index(:), &
2276 row_offset(:), small_list(:)
2277 INTEGER, POINTER :: row_size(:)
2278 LOGICAL, ALLOCATABLE :: single_rank(:)
2279 REAL(kind=dp), ALLOCATABLE :: atom_rhs(:, :), buffer(:, :), &
2280 diagonal(:), gram(:, :), &
2281 local_rhs(:, :), phi(:, :), radius(:)
2282 TYPE(dbcsr_distribution_type) :: distribution
2283 TYPE(mp_para_env_type), POINTER :: column_env, para_env
2284 TYPE(qs_kind_type), POINTER :: qs_kinds(:)
2285
2286 CALL timeset(routinen, handle)
2287 CALL get_qs_env(qs_env, para_env=para_env, qs_kind_set=qs_kinds)
2288 CALL dbcsr_get_info(mat_rhs, distribution=distribution, row_blk_size=row_size)
2289 CALL dbcsr_distribution_get(distribution, mypcol=mypcol, npcols=npcol)
2290 ALLOCATE (column_env)
2291 CALL column_env%from_split(para_env, mypcol)
2292 natom = bs_env%n_atom
2293 ALLOCATE (radius(natom), all_index(SIZE(grid, 2)), row_offset(SIZE(row_size)))
2294 CALL compute_auto_ri_grid_radii(bs_env, radius)
2295 CALL classify_z_lp_atoms(bs_env, grid, radius, &
2296 bs_env%auto_ri%sizes_opt_RI, grid_size, &
2297 small_list, n_small, big_list, n_big, group_size)
2298 ALLOCATE (single_rank(natom), source=.false.)
2299 single_rank(small_list(:n_small)) = .true.
2300 DO i = 1, SIZE(all_index)
2301 all_index(i) = i
2302 END DO
2303 row_offset(1) = 0
2304 DO i = 2, SIZE(row_size)
2305 row_offset(i) = row_offset(i - 1) + row_size(i - 1)
2306 END DO
2307 DO base = mypcol + 1, natom, npcol*column_env%num_pe
2308 CALL timeset(routinen//'_gather_rhs', handle_gather)
2309 DO slot = 0, column_env%num_pe - 1
2310 atom_index = base + slot*npcol
2311 IF (atom_index > natom) EXIT
2312 IF (.NOT. single_rank(atom_index)) cycle
2313 ncol = bs_env%auto_ri%sizes_opt_RI(atom_index)
2314 IF (ncol == 0) cycle
2315 ALLOCATE (buffer(SIZE(grid, 2), ncol))
2316 CALL extract_atom_d_lp(mat_rhs, atom_index, all_index, row_offset, buffer)
2317 CALL column_env%sum(buffer, slot)
2318 IF (column_env%mepos == slot) THEN
2319 CALL move_alloc(buffer, atom_rhs)
2320 ELSE
2321 DEALLOCATE (buffer)
2322 END IF
2323 END DO
2324 CALL timestop(handle_gather)
2325 atom_index = base + column_env%mepos*npcol
2326 IF (atom_index > natom) cycle
2327 IF (.NOT. single_rank(atom_index)) cycle
2328 ncol = bs_env%auto_ri%sizes_opt_RI(atom_index)
2329 IF (ncol == 0) cycle
2330 CALL build_phi_on_sphere(bs_env, qs_kinds, grid, atom_index, &
2331 radius(atom_index), bs_env%i_ao_end_from_atom(natom), &
2332 local_index, ngrid, phi, ao_map, nao)
2333 ALLOCATE (local_rhs(ngrid, ncol), diagonal(ngrid))
2334 DO i = 1, ngrid
2335 local_rhs(i, :) = atom_rhs(local_index(i), :)
2336 END DO
2337 DEALLOCATE (atom_rhs)
2338 CALL build_gram_jacobi_blas(phi, ngrid, nao, bs_env%ri_rs%tikhonov, gram, diagonal)
2339 CALL scale_rows_by_diag(local_rhs, diagonal, ngrid, ncol)
2340 CALL dpotrf('L', ngrid, gram, ngrid, info)
2341 cpassert(info == 0)
2342 CALL dpotrs('L', ngrid, ncol, gram, ngrid, local_rhs, ngrid, info)
2343 cpassert(info == 0)
2344 CALL scale_rows_by_diag(local_rhs, diagonal, ngrid, ncol)
2345 CALL store_z_lp_columns(mat_z, local_rhs, local_index, ngrid, ncol, atom_index, &
2346 row_size, row_offset, 0.0_dp)
2347 DEALLOCATE (local_rhs, diagonal, gram, phi, ao_map, local_index)
2348 END DO
2349 IF (n_big > 0) THEN
2350 CALL fit_distributed_auto_ri_z_lp(qs_env, bs_env, grid, mat_rhs, mat_z, radius, &
2351 big_list(:n_big), group_size, row_size, row_offset, &
2352 all_index)
2353 END IF
2354 DEALLOCATE (radius, all_index, row_offset, single_rank, grid_size, small_list, big_list)
2355 CALL column_env%free()
2356 DEALLOCATE (column_env)
2357 CALL dbcsr_finalize(mat_z)
2358 CALL timestop(handle)
2359 END SUBROUTINE fit_auto_ri_z_lp
2360
2361! **************************************************************************************************
2362!> \brief Solves Σ_l' D_ll' Z_l'q = d_lp for large atomic grids with distributed Cholesky
2363!> factorization. Each d_lp block is gathered once and distributed over its assigned rank
2364!> group.
2365!> \param qs_env ...
2366!> \param bs_env ...
2367!> \param grid ...
2368!> \param mat_rhs ...
2369!> \param mat_z ...
2370!> \param radius ...
2371!> \param atom_list ...
2372!> \param group_size ...
2373!> \param row_size ...
2374!> \param row_offset ...
2375!> \param all_index ...
2376! **************************************************************************************************
2377 SUBROUTINE fit_distributed_auto_ri_z_lp(qs_env, bs_env, grid, mat_rhs, mat_z, radius, &
2378 atom_list, group_size, row_size, row_offset, &
2379 all_index)
2380 TYPE(qs_environment_type), POINTER :: qs_env
2381 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2382 REAL(kind=dp), INTENT(IN) :: grid(:, :)
2383 TYPE(dbcsr_type), INTENT(INOUT) :: mat_rhs, mat_z
2384 REAL(kind=dp), INTENT(IN) :: radius(:)
2385 INTEGER, INTENT(IN) :: atom_list(:), group_size, row_size(:), &
2386 row_offset(:), all_index(:)
2387
2388 CHARACTER(LEN=*), PARAMETER :: routinen = 'fit_distributed_auto_ri_z_lp'
2389
2390 INTEGER :: atom_index, base, handle, i, info, &
2391 my_group, nao, ncol, ngrid, ngroups, &
2392 root, slot
2393 INTEGER, ALLOCATABLE :: ao_map(:), local_index(:)
2394 REAL(kind=dp), ALLOCATABLE :: atom_rhs(:, :), buffer(:, :), &
2395 diagonal(:), local_rhs(:, :), phi(:, :)
2396 TYPE(cp_blacs_env_type), POINTER :: blacs_env
2397 TYPE(cp_fm_struct_type), POINTER :: gram_struct, rhs_struct
2398 TYPE(cp_fm_type) :: gram, rhs
2399 TYPE(mp_para_env_type), POINTER :: group_env, para_env
2400 TYPE(qs_kind_type), POINTER :: qs_kinds(:)
2401
2402 CALL timeset(routinen, handle)
2403 CALL get_qs_env(qs_env, para_env=para_env, qs_kind_set=qs_kinds)
2404 ngroups = max(1, para_env%num_pe/group_size)
2405 my_group = min(para_env%mepos/group_size, ngroups - 1)
2406 ALLOCATE (group_env)
2407 CALL group_env%from_split(para_env, my_group)
2408 NULLIFY (blacs_env, gram_struct, rhs_struct)
2409 CALL cp_blacs_env_create(blacs_env=blacs_env, para_env=group_env)
2410 DO base = 1, SIZE(atom_list), ngroups
2411 DO slot = 0, ngroups - 1
2412 IF (base + slot > SIZE(atom_list)) EXIT
2413 atom_index = atom_list(base + slot)
2414 ncol = bs_env%auto_ri%sizes_opt_RI(atom_index)
2415 IF (ncol == 0) cycle
2416 root = slot*group_size
2417 ALLOCATE (buffer(SIZE(grid, 2), ncol))
2418 CALL extract_atom_d_lp(mat_rhs, atom_index, all_index, row_offset, buffer)
2419 CALL para_env%sum(buffer, root)
2420 IF (para_env%mepos == root) THEN
2421 CALL move_alloc(buffer, atom_rhs)
2422 ELSE
2423 DEALLOCATE (buffer)
2424 END IF
2425 END DO
2426 IF (base + my_group > SIZE(atom_list)) cycle
2427 atom_index = atom_list(base + my_group)
2428 ncol = bs_env%auto_ri%sizes_opt_RI(atom_index)
2429 IF (ncol == 0) cycle
2430 IF (group_env%mepos /= 0) ALLOCATE (atom_rhs(SIZE(grid, 2), ncol))
2431 CALL group_env%bcast(atom_rhs, 0)
2432 CALL build_phi_on_sphere(bs_env, qs_kinds, grid, atom_index, &
2433 radius(atom_index), bs_env%i_ao_end_from_atom(bs_env%n_atom), &
2434 local_index, ngrid, phi, ao_map, nao)
2435 ALLOCATE (local_rhs(ngrid, ncol), diagonal(ngrid))
2436 DO i = 1, ngrid
2437 local_rhs(i, :) = atom_rhs(local_index(i), :)
2438 END DO
2439 DEALLOCATE (atom_rhs)
2440 CALL build_jacobi_diag_from_phi(phi, ngrid, nao, diagonal)
2441 CALL scale_rows_by_diag(local_rhs, diagonal, ngrid, ncol)
2442 CALL solve_d_lp_distributed(phi, diagonal, local_rhs, ngrid, nao, ncol, &
2443 bs_env%ri_rs%tikhonov, group_env, blacs_env, &
2444 gram_struct, rhs_struct, gram, rhs, info)
2445 cpassert(info == 0)
2446 CALL scale_rows_by_diag(local_rhs, diagonal, ngrid, ncol)
2447 IF (group_env%mepos == 0) THEN
2448 CALL store_z_lp_columns(mat_z, local_rhs, local_index, ngrid, ncol, atom_index, &
2449 row_size, row_offset, 0.0_dp)
2450 END IF
2451 DEALLOCATE (local_rhs, diagonal, phi, ao_map, local_index)
2452 END DO
2453 CALL cp_blacs_env_release(blacs_env)
2454 CALL group_env%free()
2455 DEALLOCATE (group_env)
2456 CALL timestop(handle)
2457 END SUBROUTINE fit_distributed_auto_ri_z_lp
2458
2459! **************************************************************************************************
2460!> \brief Splits the atoms of the Z_lP solve into a single-rank list ("small", Phase A: LAPACK
2461!> dpotrf/dpotrs on one rank) and a distributed list ("big", Phase B: ScaLAPACK
2462!> pdpotrf/pdpotrs over a rank subgroup of size G), and sizes G.
2463!> AUTO mode (N_PROCS_PER_ATOM_Z_LP <= 0, the default): estimate each atom's single-rank
2464!> peak memory
2465!> peak(P) = 8*n_local_grid(P)^2 (dense matrix D'_ll', stored in D_local)
2466!> + 8*n_local_grid(P)*n_ao_used(P) (phi_local)
2467!> + 8*n_local_grid(P)*n_RI(P)*(1+n_threads) (d_lp + OMP partials)
2468!> and send atoms whose peak exceeds mem_safety * available-memory-per-proc to the
2469!> distributed path; G is auto-sized so the biggest atom's distributed D_local (/G)
2470!> fits alongside the replicated phi_local + d_lp.
2471!> MANUAL mode (> 0): 1 forces the single-rank path for every atom; > 1 keeps the
2472!> memory-based classification but forces that fixed subgroup size G.
2473!> In every mode G is floored by the ScaLAPACK 32-bit index limit (a local block-cyclic
2474!> slice of ~n_local_grid^2/G elements must stay below 2^31 or pdpotrf segfaults).
2475!> \param bs_env ...
2476!> \param ri_rs_grid_points ...
2477!> \param cutoff_ri_per_atom ...
2478!> \param ri_blk_sizes per-atom ...
2479!> \param n_local_grid_atom ...
2480!> \param small_list ...
2481!> \param n_small ...
2482!> \param big_list ...
2483!> \param n_big ...
2484!> \param G ...
2485! **************************************************************************************************
2486 SUBROUTINE classify_z_lp_atoms(bs_env, ri_rs_grid_points, cutoff_ri_per_atom, ri_blk_sizes, &
2487 n_local_grid_atom, small_list, n_small, big_list, n_big, G)
2488
2489!$ USE OMP_LIB, ONLY: omp_get_max_threads
2490
2491 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2492 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ri_rs_grid_points
2493
2494 REAL(kind=dp), DIMENSION(:), INTENT(IN) :: cutoff_ri_per_atom
2495 INTEGER, DIMENSION(:), INTENT(IN) :: ri_blk_sizes
2496 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: n_local_grid_atom, small_list, big_list
2497 INTEGER, INTENT(OUT) :: n_small, n_big, g
2498 CHARACTER(LEN=*), PARAMETER :: routinen = 'classify_z_lp_atoms'
2499
2500 INTEGER :: handle
2501
2502 ! Conservative fraction of measured available memory usable per rank for the Z_lP
2503 REAL(kind=dp), PARAMETER :: mem_safety = 0.8_dp
2504
2505 ! ScaLAPACK/BLACS index the per-rank local block-cyclic slice (~n_local_grid^2/G
2506 ! elements) with 32-bit integers; keep it safely below 2^31 or pdpotrf segfaults.
2507 REAL(kind=dp), PARAMETER :: scalapack_loc_limit = 2.0e9_dp
2508
2509 INTEGER :: g_atom, g_int32, g_int32_max, l, &
2510 n_ao_used_atom, n_grid_total, &
2511 n_local_grid, natom, nthreads_cls, &
2512 p_loop_atom
2513 LOGICAL :: auto_mode
2514 REAL(kind=dp) :: budget_bytes, cutoff_ri, dlp_bytes, &
2515 mem_avail_gb, ng, nri, peak_bytes, &
2516 phi_bytes
2517 REAL(kind=dp), DIMENSION(3) :: pos_p
2518 TYPE(mp_para_env_type), POINTER :: para_env
2519 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2520
2521 CALL timeset(routinen, handle)
2522
2523 para_env => bs_env%para_env
2524 particle_set => bs_env%ri_rs%particle_set
2525 natom = bs_env%n_atom
2526 n_grid_total = bs_env%ri_rs%n_grid_points
2527 cpassert(SIZE(ri_rs_grid_points, 2) == n_grid_total)
2528
2529 ! Per-atom sphere size: n_local_grid(P) = number of l with |r_l - R_P| <= cutoff_ri(P).
2530 ! It sets both the memory footprint (D_local is n_local_grid^2) and the solve
2531 ! cost (~n_local_grid^3), so it drives classification and the LPT load balancing.
2532 ALLOCATE (n_local_grid_atom(natom), small_list(natom), big_list(natom))
2533 DO p_loop_atom = 1, natom
2534 pos_p(:) = particle_set(p_loop_atom)%r(:)
2535 cutoff_ri = cutoff_ri_per_atom(p_loop_atom)
2536 n_local_grid = 0
2537 DO l = 1, n_grid_total
2538 IF (sum((ri_rs_grid_points(1:3, l) - pos_p(1:3))**2) <= cutoff_ri**2) THEN
2539 n_local_grid = n_local_grid + 1
2540 END IF
2541 END DO
2542 n_local_grid_atom(p_loop_atom) = n_local_grid
2543 END DO
2544
2545 nthreads_cls = 1
2546!$ nthreads_cls = omp_get_max_threads()
2547 ! N_PROCS_PER_ATOM_Z_LP: -1 (default) = AUTO (classify by memory, auto-size G);
2548 ! 1 = force single-rank BLAS for every atom; >1 = classify by memory but use this
2549 ! fixed subgroup size G for the big atoms.
2550 auto_mode = (bs_env%ri_rs%n_procs_per_atom_z_lp <= 0)
2551 CALL mp_mem_avail_per_rank_gb(bs_env%para_env, mem_avail_gb) ! collective over all ranks
2552 budget_bytes = mem_safety*mem_avail_gb*1.0e9_dp
2553
2554 n_small = 0
2555 n_big = 0
2556 g = 1
2557 g_atom = 1 ! max G a big atom needs (memory + ScaLAPACK int32 floor)
2558 g_int32_max = 1 ! max ScaLAPACK-int32 floor over the distributed atoms
2559 IF (bs_env%ri_rs%n_procs_per_atom_z_lp == 1) THEN
2560 ! Force single-rank BLAS for every atom.
2561 DO p_loop_atom = 1, natom
2562 n_small = n_small + 1
2563 small_list(n_small) = p_loop_atom
2564 END DO
2565 ELSE IF (mem_avail_gb <= 0.0_dp) THEN
2566 ! No /proc/meminfo => cannot size by memory.
2567 IF (auto_mode) THEN
2568 IF (bs_env%unit_nr > 0) THEN
2569 cpwarn("RI-RS Z_lP: no meminfo; single-rank solve for all atoms")
2570 END IF
2571 DO p_loop_atom = 1, natom
2572 n_small = n_small + 1
2573 small_list(n_small) = p_loop_atom
2574 END DO
2575 ELSE
2576 ! Fixed G, no meminfo: distribute all atoms; still floor G by the int32 limit.
2577 DO p_loop_atom = 1, natom
2578 ng = real(n_local_grid_atom(p_loop_atom), dp)
2579 g_int32_max = max(g_int32_max, ceiling(ng*ng/scalapack_loc_limit))
2580 n_big = n_big + 1
2581 big_list(n_big) = p_loop_atom
2582 END DO
2583 g = min(bs_env%ri_rs%n_procs_per_atom_z_lp, para_env%num_pe)
2584 IF (g < g_int32_max) THEN
2585 g = min(g_int32_max, para_env%num_pe)
2586 IF (bs_env%unit_nr > 0) THEN
2587 cpwarn("RI-RS Z_lP: raised G to avoid ScaLAPACK overflow")
2588 END IF
2589 END IF
2590 END IF
2591 ELSE
2592 ! Classify by memory: peak (D_local + phi_local + d_lp) vs budget. Small -> BLAS,
2593 ! big -> distributed. Same classification for AUTO and fixed-G modes.
2594 DO p_loop_atom = 1, natom
2595 ng = real(n_local_grid_atom(p_loop_atom), dp)
2596 nri = real(ri_blk_sizes(p_loop_atom), dp)
2597 CALL get_n_ao_in_sphere(bs_env, p_loop_atom, &
2598 cutoff_ri_per_atom(p_loop_atom), n_ao_used_atom)
2599 phi_bytes = 8.0_dp*ng*real(n_ao_used_atom, dp)
2600 dlp_bytes = 8.0_dp*ng*nri*real(1 + nthreads_cls, dp)
2601 peak_bytes = 8.0_dp*ng*ng + phi_bytes + dlp_bytes
2602 IF (peak_bytes <= budget_bytes) THEN
2603 n_small = n_small + 1
2604 small_list(n_small) = p_loop_atom
2605 ELSE
2606 n_big = n_big + 1
2607 big_list(n_big) = p_loop_atom
2608 ! G must satisfy BOTH: (a) memory — distributed D_local (/G) fits next to the
2609 ! replicated phi_local + d_lp; (b) ScaLAPACK — local ~ng^2/G below the int32 limit.
2610 g_int32 = ceiling(ng*ng/scalapack_loc_limit)
2611 g_int32_max = max(g_int32_max, g_int32)
2612 g_atom = max(g_atom, g_int32, &
2613 ceiling(8.0_dp*ng*ng/max(budget_bytes - phi_bytes - dlp_bytes, 1.0_dp)))
2614 END IF
2615 END DO
2616 IF (n_big > 0) THEN
2617 IF (auto_mode) THEN
2618 ! Auto-size G from the most demanding big atom.
2619 IF (g_atom > para_env%num_pe) THEN
2620 CALL cp_abort(__location__, &
2621 "RI-RS Z_lP: an atom is too large to fit even when "// &
2622 "distributed over all ranks. Add nodes, use fewer MPI ranks "// &
2623 "per node, lower CUTOFF_RADIUS_RL_RI, or raise EPS_FILTER "// &
2624 "for more grid screening.")
2625 END IF
2626 g = min(max(g_atom, 2), para_env%num_pe)
2627 ELSE
2628 ! Fixed G from the keyword. Hard-floor by the ScaLAPACK int32 limit (below it
2629 ! pdpotrf segfaults); warn if it is still below the memory recommendation.
2630 g = min(bs_env%ri_rs%n_procs_per_atom_z_lp, para_env%num_pe)
2631 IF (g < g_int32_max) THEN
2632 g = min(g_int32_max, para_env%num_pe)
2633 IF (bs_env%unit_nr > 0) THEN
2634 cpwarn("RI-RS Z_lP: raised G to avoid ScaLAPACK overflow")
2635 END IF
2636 ELSE IF (g < g_atom .AND. bs_env%unit_nr > 0) THEN
2637 cpwarn("RI-RS Z_lP: N_PROCS_PER_ATOM_Z_LP too small for the largest atom")
2638 END IF
2639 END IF
2640 END IF
2641 END IF
2642
2643 CALL timestop(handle)
2644
2645 END SUBROUTINE classify_z_lp_atoms
2646
2647! **************************************************************************************************
2648!> \brief Number of AO basis functions that can be non-zero inside the RI-RS integration sphere
2649!> \param bs_env ...
2650!> \param atom_P ...
2651!> \param cutoff_ri ...
2652!> \param n_ao_used ...
2653! **************************************************************************************************
2654 SUBROUTINE get_n_ao_in_sphere(bs_env, atom_P, cutoff_ri, n_ao_used)
2655
2656 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2657 INTEGER, INTENT(IN) :: atom_p
2658 REAL(kind=dp), INTENT(IN) :: cutoff_ri
2659 INTEGER, INTENT(OUT) :: n_ao_used
2660
2661 CHARACTER(LEN=*), PARAMETER :: routinen = 'get_n_ao_in_sphere'
2662
2663 INTEGER :: handle, ri_atom
2664 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2665
2666 CALL timeset(routinen, handle)
2667
2668 particle_set => bs_env%ri_rs%particle_set
2669 n_ao_used = 0
2670 DO ri_atom = 1, bs_env%n_atom
2671 IF (norm2(particle_set(ri_atom)%r(:) - particle_set(atom_p)%r(:)) > &
2672 bs_env%ri_rs%radius_ao_per_atom(ri_atom) + cutoff_ri) cycle
2673 n_ao_used = n_ao_used + bs_env%i_ao_end_from_atom(ri_atom) - &
2674 bs_env%i_ao_start_from_atom(ri_atom) + 1
2675 END DO
2676
2677 CALL timestop(handle)
2678
2679 END SUBROUTINE get_n_ao_in_sphere
2680
2681! **************************************************************************************************
2682!> \brief Builds the sphere-local AO matrix phi_local(l, μ) = ϕ_μ(r_l) for one RI atom P
2683!> \param bs_env ...
2684!> \param qs_kind_set ...
2685!> \param ri_rs_grid_points ...
2686!> \param atom_P ...
2687!> \param cutoff_ri ...
2688!> \param n_ao_total ...
2689!> \param local_grid_idx ...
2690!> \param n_local_grid ...
2691!> \param phi_local ...
2692!> \param ao_col_map ...
2693!> \param n_ao_used ...
2694!> \param center ...
2695! **************************************************************************************************
2696 SUBROUTINE build_phi_on_sphere(bs_env, qs_kind_set, ri_rs_grid_points, &
2697 atom_P, cutoff_ri, n_ao_total, local_grid_idx, n_local_grid, &
2698 phi_local, ao_col_map, n_ao_used, center)
2699
2700 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2701 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
2702 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: ri_rs_grid_points
2703 INTEGER, INTENT(IN) :: atom_p
2704 REAL(kind=dp), INTENT(IN) :: cutoff_ri
2705 INTEGER, INTENT(IN) :: n_ao_total
2706 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: local_grid_idx
2707 INTEGER, INTENT(OUT) :: n_local_grid
2708 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :), &
2709 INTENT(OUT) :: phi_local
2710 INTEGER, ALLOCATABLE, DIMENSION(:), INTENT(OUT) :: ao_col_map
2711 INTEGER, INTENT(OUT) :: n_ao_used
2712 REAL(kind=dp), DIMENSION(3), INTENT(IN), OPTIONAL :: center
2713
2714 CHARACTER(LEN=*), PARAMETER :: routinen = 'build_phi_on_sphere'
2715
2716 INTEGER :: col_end, col_start, handle, j, k, l, &
2717 loc_idx, n_grid_total, n_keep, ri_atom
2718 REAL(kind=dp) :: d_sp, dist, r2_threshold
2719 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: w_pt
2720 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: phi_keep, sphere_grid
2721 REAL(kind=dp), DIMENSION(3) :: pos_p
2722 TYPE(cell_type), POINTER :: cell
2723 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
2724
2725 CALL timeset(routinen, handle)
2726
2727 cell => bs_env%ri_rs%cell
2728 particle_set => bs_env%ri_rs%particle_set
2729 ! AUTO_RI may pass only the global grid points needed for the current atom block.
2730 n_grid_total = SIZE(ri_rs_grid_points, 2)
2731 IF (PRESENT(center)) THEN
2732 pos_p(:) = center(:)
2733 ELSE
2734 pos_p(:) = particle_set(atom_p)%r(:)
2735 END IF
2736
2737 n_local_grid = 0
2738 DO l = 1, n_grid_total
2739 dist = norm2(ri_rs_grid_points(1:3, l) - pos_p(1:3))
2740 IF (dist <= cutoff_ri) n_local_grid = n_local_grid + 1
2741 END DO
2742
2743 ALLOCATE (local_grid_idx(n_local_grid))
2744
2745 n_local_grid = 0
2746 DO l = 1, n_grid_total
2747 dist = norm2(ri_rs_grid_points(1:3, l) - pos_p(1:3))
2748 IF (dist <= cutoff_ri) THEN
2749 n_local_grid = n_local_grid + 1
2750 local_grid_idx(n_local_grid) = l
2751 END IF
2752 END DO
2753
2754 ALLOCATE (sphere_grid(3, n_local_grid))
2755 DO loc_idx = 1, n_local_grid
2756 sphere_grid(:, loc_idx) = ri_rs_grid_points(:, local_grid_idx(loc_idx))
2757 END DO
2758
2759 ! Only AOs on atoms that reach into the sphere can be non-zero here
2760 ALLOCATE (ao_col_map(n_ao_total))
2761 ao_col_map(:) = 0
2762 n_ao_used = 0
2763 DO ri_atom = 1, bs_env%n_atom
2764 d_sp = norm2(particle_set(ri_atom)%r(:) - pos_p(:))
2765 IF (d_sp > bs_env%ri_rs%radius_ao_per_atom(ri_atom) + cutoff_ri) cycle
2766
2767 DO j = bs_env%i_ao_start_from_atom(ri_atom), bs_env%i_ao_end_from_atom(ri_atom)
2768 n_ao_used = n_ao_used + 1
2769 ao_col_map(j) = n_ao_used
2770 END DO
2771 END DO
2772
2773 ALLOCATE (phi_local(n_local_grid, n_ao_used))
2774 phi_local = 0.0_dp
2775
2776 DO ri_atom = 1, bs_env%n_atom
2777 d_sp = norm2(particle_set(ri_atom)%r(:) - pos_p(:))
2778 IF (d_sp > bs_env%ri_rs%radius_ao_per_atom(ri_atom) + cutoff_ri) cycle
2779
2780 col_start = ao_col_map(bs_env%i_ao_start_from_atom(ri_atom))
2781 col_end = ao_col_map(bs_env%i_ao_end_from_atom(ri_atom))
2782 ! A positive CUTOFF_RADIUS_RI_AO overrides the per-atom Gaussian radius
2783 ! with a user-defined hard cutoff.
2784 IF (bs_env%ri_rs%cutoff_radius_ri_ao > 0.0_dp) THEN
2785 r2_threshold = bs_env%ri_rs%cutoff_radius_ri_ao**2
2786 ELSE
2787 r2_threshold = bs_env%ri_rs%radius_ao_per_atom(ri_atom)**2
2788 END IF
2789
2790 CALL evaluate_ao_on_points(phi_local(:, col_start:col_end), sphere_grid, &
2791 ri_atom, particle_set, qs_kind_set, cell, &
2792 cutoff_squared=r2_threshold)
2793 END DO
2794
2795 DEALLOCATE (sphere_grid)
2796
2797 IF (n_local_grid > 0) THEN
2798 ALLOCATE (w_pt(n_local_grid))
2799 !$OMP PARALLEL DO DEFAULT(NONE) &
2800 !$OMP SHARED(n_local_grid, n_ao_used, phi_local, w_pt) &
2801 !$OMP PRIVATE(l, j) SCHEDULE(STATIC)
2802 DO l = 1, n_local_grid
2803 w_pt(l) = 0.0_dp
2804 DO j = 1, n_ao_used
2805 w_pt(l) = max(w_pt(l), abs(phi_local(l, j)))
2806 END DO
2807 END DO
2808 !$OMP END PARALLEL DO
2809 n_keep = count(w_pt > bs_env%eps_filter)
2810 IF (n_keep < n_local_grid) THEN
2811 ALLOCATE (phi_keep(n_keep, n_ao_used))
2812 k = 0
2813 DO l = 1, n_local_grid
2814 IF (w_pt(l) > bs_env%eps_filter) THEN
2815 k = k + 1
2816 phi_keep(k, :) = phi_local(l, :)
2817 local_grid_idx(k) = local_grid_idx(l)
2818 END IF
2819 END DO
2820 CALL move_alloc(phi_keep, phi_local)
2821 n_local_grid = n_keep
2822 END IF
2823 DEALLOCATE (w_pt)
2824 END IF
2825
2826 CALL timestop(handle)
2827
2828 END SUBROUTINE build_phi_on_sphere
2829
2830! **************************************************************************************************
2831!> \brief Computes a three-center integral block directly in AUTO_RI contraction columns.
2832!>
2833!> For each angular momentum l, the primitive RI Gaussians on the atoms contributing
2834!> to one optimized function are collected before the contraction
2835!>
2836!> (μν|p) = Σ_P (μν|P) U_Pp .
2837!>
2838!> This avoids constructing and retaining the complete reference-basis block (μν|P).
2839!> \param int_3c ...
2840!> \param ctx ...
2841!> \param ws ...
2842!> \param atom_j ...
2843!> \param atom_k ...
2844!> \param atom_i ...
2845!> \param transform ...
2846!> \param transform_row ...
2847!> \param screened ...
2848! **************************************************************************************************
2849 SUBROUTINE build_3c_integral_block_auto_ri_ctx(int_3c, ctx, ws, atom_j, atom_k, atom_i, &
2850 transform, transform_row, screened)
2851 REAL(kind=dp), DIMENSION(:, :, :), INTENT(INOUT) :: int_3c
2852 TYPE(gw_3c_ctx_type), INTENT(IN) :: ctx
2853 TYPE(gw_3c_ws_type), INTENT(INOUT) :: ws
2854 INTEGER, INTENT(IN) :: atom_j, atom_k, atom_i
2855 REAL(kind=dp), DIMENSION(:, :), INTENT(IN) :: transform
2856 INTEGER, INTENT(IN) :: transform_row
2857 LOGICAL, INTENT(OUT), OPTIONAL :: screened
2858
2859 CHARACTER(LEN=*), PARAMETER :: routinen = 'build_3c_integral_block_auto_ri_ctx'
2860
2861 INTEGER :: handle_contract, handle_eri, ikind, iset, jkind, jset, kkind, kset, l, ncoi, &
2862 ncoj, ncok, ncol, npgf_group, nseti, nsetj, nsetk, primitive_first, sgfi, sgfj, sgfk
2863 INTEGER, DIMENSION(:), POINTER :: lmax_i, lmax_j, lmax_k, lmin_i, lmin_j, &
2864 lmin_k, npgfi, npgfj, npgfk, nsgfi, &
2865 nsgfj, nsgfk
2866 INTEGER, DIMENSION(:, :), POINTER :: first_sgf_i, first_sgf_j, first_sgf_k
2867 REAL(kind=dp) :: dij, dik, djk, group_radius, &
2868 kind_radius_i, kind_radius_j, &
2869 kind_radius_k, sijk_ext
2870 REAL(kind=dp), ALLOCATABLE, DIMENSION(:) :: rpgf_group, zet_group
2871 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :) :: spi_group
2872 REAL(kind=dp), ALLOCATABLE, DIMENSION(:, :, :) :: sijk, sijk_contr
2873 REAL(kind=dp), DIMENSION(3) :: ri, rij, rik, rj, rjk, rk
2874 REAL(kind=dp), DIMENSION(:), POINTER :: set_radius_i, set_radius_j, set_radius_k
2875 REAL(kind=dp), DIMENSION(:, :), POINTER :: rpgf_i, rpgf_j, rpgf_k, zeti, zetj, zetk
2876
2877 IF (PRESENT(screened)) screened = .false.
2878 ri = pbc(ctx%particle_set(atom_i)%r(1:3), ctx%cell)
2879 rj = pbc(ctx%particle_set(atom_j)%r(1:3), ctx%cell)
2880 rk = pbc(ctx%particle_set(atom_k)%r(1:3), ctx%cell)
2881 rjk = rk - rj
2882 rij = rj - ri
2883 rik = rk - ri
2884 djk = norm2(rjk)
2885 dij = norm2(rij)
2886 dik = norm2(rik)
2887
2888 ikind = ctx%kind_of(atom_i)
2889 jkind = ctx%kind_of(atom_j)
2890 kkind = ctx%kind_of(atom_k)
2891 CALL get_gto_basis_set(ctx%basis_i(ikind)%gto_basis_set, first_sgf=first_sgf_i, &
2892 lmax=lmax_i, lmin=lmin_i, npgf=npgfi, nset=nseti, &
2893 nsgf_set=nsgfi, pgf_radius=rpgf_i, set_radius=set_radius_i, &
2894 zet=zeti, kind_radius=kind_radius_i)
2895 CALL get_gto_basis_set(ctx%basis_j(jkind)%gto_basis_set, first_sgf=first_sgf_j, &
2896 lmax=lmax_j, lmin=lmin_j, npgf=npgfj, nset=nsetj, &
2897 nsgf_set=nsgfj, pgf_radius=rpgf_j, set_radius=set_radius_j, &
2898 zet=zetj, kind_radius=kind_radius_j)
2899 CALL get_gto_basis_set(ctx%basis_k(kkind)%gto_basis_set, first_sgf=first_sgf_k, &
2900 lmax=lmax_k, lmin=lmin_k, npgf=npgfk, nset=nsetk, &
2901 nsgf_set=nsgfk, pgf_radius=rpgf_k, set_radius=set_radius_k, &
2902 zet=zetk, kind_radius=kind_radius_k)
2903
2904 IF (kind_radius_j + kind_radius_i + ctx%dr_ij < dij .OR. &
2905 kind_radius_j + kind_radius_k + ctx%dr_jk < djk .OR. &
2906 kind_radius_k + kind_radius_i + ctx%dr_ik < dik) THEN
2907 IF (PRESENT(screened)) screened = .true.
2908 RETURN
2909 END IF
2910
2911 ncol = SIZE(transform, 2)
2912 cpassert(SIZE(int_3c, 3) == ncol)
2913 DO l = 0, ctx%maxli
2914 npgf_group = 0
2915 group_radius = 0.0_dp
2916 DO iset = 1, nseti
2917 IF (lmin_i(iset) /= l .OR. lmax_i(iset) /= l) cycle
2918 npgf_group = npgf_group + npgfi(iset)
2919 group_radius = max(group_radius, set_radius_i(iset))
2920 END DO
2921 IF (npgf_group == 0) cycle
2922 ncoi = npgf_group*ncoset(l)
2923 ALLOCATE (zet_group(npgf_group), rpgf_group(npgf_group))
2924 ALLOCATE (spi_group(ncoi, ncol), source=0.0_dp)
2925 primitive_first = 1
2926 DO iset = 1, nseti
2927 IF (lmin_i(iset) /= l .OR. lmax_i(iset) /= l) cycle
2928 zet_group(primitive_first:primitive_first + npgfi(iset) - 1) = &
2929 zeti(1:npgfi(iset), iset)
2930 rpgf_group(primitive_first:primitive_first + npgfi(iset) - 1) = &
2931 rpgf_i(1:npgfi(iset), iset)
2932 sgfi = first_sgf_i(1, iset)
2933 spi_group((primitive_first - 1)*ncoset(l) + 1: &
2934 (primitive_first + npgfi(iset) - 1)*ncoset(l), :) = &
2935 matmul(ctx%spi(iset, ikind)%array, &
2936 transform(transform_row + sgfi - 1: &
2937 transform_row + sgfi + nsgfi(iset) - 2, :))
2938 primitive_first = primitive_first + npgfi(iset)
2939 END DO
2940
2941 DO jset = 1, nsetj
2942 IF (set_radius_j(jset) + group_radius + ctx%dr_ij < dij) cycle
2943 DO kset = 1, nsetk
2944 IF (set_radius_j(jset) + set_radius_k(kset) + ctx%dr_jk < djk) cycle
2945 IF (set_radius_k(kset) + group_radius + ctx%dr_ik < dik) cycle
2946 ncoj = npgfj(jset)*ncoset(lmax_j(jset))
2947 ncok = npgfk(kset)*ncoset(lmax_k(kset))
2948 sgfj = first_sgf_j(1, jset)
2949 sgfk = first_sgf_k(1, kset)
2950 IF (ncoj*ncok*ncoi <= 0) cycle
2951 ALLOCATE (sijk(ncoj, ncok, ncoi), source=0.0_dp)
2952 CALL timeset(routinen//'_eri', handle_eri)
2953 CALL eri_3center(sijk, &
2954 lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), &
2955 rpgf_j(:, jset), rj, &
2956 lmin_k(kset), lmax_k(kset), npgfk(kset), zetk(:, kset), &
2957 rpgf_k(:, kset), rk, l, l, npgf_group, zet_group, &
2958 rpgf_group, ri, djk, dij, dik, ws%lib, ctx%potential_parameter, &
2959 int_abc_ext=sijk_ext)
2960 CALL timestop(handle_eri)
2961 ALLOCATE (sijk_contr(nsgfj(jset), nsgfk(kset), ncol))
2962 CALL timeset(routinen//'_contract', handle_contract)
2963 CALL abc_contract_xsmm(sijk_contr, sijk, ctx%tspj(jset, jkind)%array, &
2964 ctx%spk(kset, kkind)%array, spi_group, ncoj, ncok, ncoi, &
2965 nsgfj(jset), nsgfk(kset), ncol, ws%cpp_buffer, ws%ccp_buffer)
2966 CALL timestop(handle_contract)
2967 DEALLOCATE (sijk)
2968 int_3c(sgfj:sgfj + nsgfj(jset) - 1, sgfk:sgfk + nsgfk(kset) - 1, :) = &
2969 int_3c(sgfj:sgfj + nsgfj(jset) - 1, sgfk:sgfk + nsgfk(kset) - 1, :) + &
2970 sijk_contr
2971 DEALLOCATE (sijk_contr)
2972 END DO
2973 END DO
2974 DEALLOCATE (zet_group, rpgf_group, spi_group)
2975 END DO
2976
2977 END SUBROUTINE build_3c_integral_block_auto_ri_ctx
2978
2979! **************************************************************************************************
2980!> \brief Returns the reference RI basis size of one atom.
2981!> \param bs_env ...
2982!> \param iatom ...
2983!> \return ...
2984! **************************************************************************************************
2985 INTEGER FUNCTION get_ref_ri_size(bs_env, iatom) RESULT(n)
2986 TYPE(post_scf_bandstructure_type), POINTER :: bs_env
2987 INTEGER, INTENT(IN) :: iatom
2988
2989 INTEGER :: ikind
2990
2991 ikind = bs_env%ri_rs%particle_set(iatom)%atomic_kind%kind_number
2992 n = bs_env%basis_set_RI(ikind)%gto_basis_set%nsgf
2993
2994 END FUNCTION get_ref_ri_size
2995
2996END MODULE gw_ri_rs_compute_z_lp
static GRID_HOST_DEVICE int idx(const orbital a)
Return coset index of given orbital angular momentum.
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
Contraction of integrals over primitive Cartesian Gaussians based on the contraction matrix sphi whic...
subroutine, public abc_contract_xsmm(abcint, sabc, sphi_a, sphi_b, sphi_c, ncoa, ncob, ncoc, nsgfa, nsgfb, nsgfc, cpp_buffer, ccp_buffer, prefac, pstfac)
3-center contraction routine from primitive cartesian Gaussians to spherical Gaussian functions using...
Definition atom.F:9
Define the atomic kind types and their sub types.
subroutine, public get_gto_basis_set(gto_basis_set, name, aliases, norm_type, kind_radius, ncgf, nset, nsgf, cgf_symbol, sgf_symbol, norm_cgf, set_radius, lmax, lmin, lx, ly, lz, m, ncgf_set, npgf, nsgf_set, nshell, cphi, pgf_radius, sphi, scon, zet, first_cgf, first_sgf, l, last_cgf, last_sgf, n, gcc, maxco, maxl, maxpgf, maxsgf_set, maxshell, maxso, nco_sum, npgf_sum, nshell_sum, maxder, short_kind_radius, npgf_seg_sum, ccon)
...
Handles all functions related to the CELL.
Definition cell_types.F:15
methods related to the blacs parallel environment
subroutine, public cp_blacs_env_release(blacs_env)
releases the given blacs_env
subroutine, public cp_blacs_env_create(blacs_env, para_env, blacs_grid_layout, blacs_repeatable, row_major, grid_2d)
allocates and initializes a type that represent a blacs context
subroutine, public dbcsr_distribution_release(dist)
...
subroutine, public dbcsr_distribution_new(dist, template, group, pgrid, row_dist, col_dist, reuse_arrays)
...
subroutine, public dbcsr_get_block_p(matrix, row, col, block, found, row_size, col_size)
...
subroutine, public dbcsr_multiply(transa, transb, alpha, matrix_a, matrix_b, beta, matrix_c, first_row, last_row, first_column, last_column, first_k, last_k, retain_sparsity, filter_eps, flop)
...
subroutine, public dbcsr_get_info(matrix, nblkrows_total, nblkcols_total, nfullrows_total, nfullcols_total, nblkrows_local, nblkcols_local, nfullrows_local, nfullcols_local, my_prow, my_pcol, local_rows, local_cols, proc_row_dist, proc_col_dist, row_blk_size, col_blk_size, row_blk_offset, col_blk_offset, distribution, name, matrix_type, group)
...
subroutine, public dbcsr_filter(matrix, eps)
...
subroutine, public dbcsr_binary_write(matrix, filepath)
...
subroutine, public dbcsr_finalize(matrix)
...
subroutine, public dbcsr_set(matrix, alpha)
...
subroutine, public dbcsr_release(matrix)
...
subroutine, public dbcsr_binary_read(filepath, distribution, matrix_new)
...
subroutine, public dbcsr_put_block(matrix, row, col, block, summation)
...
subroutine, public dbcsr_distribution_get(dist, row_dist, col_dist, nrows, ncols, has_threads, group, mynode, numnodes, nprows, npcols, myprow, mypcol, pgrid, subgroups_defined, prow_group, pcol_group)
...
subroutine, public dbcsr_reserve_all_blocks(matrix)
Reserves all blocks.
represent the structure of a full matrix
represent a full matrix distributed on many processors
Definition cp_fm_types.F:15
various routines to log and control the output. The idea is that decisions about where to log should ...
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
routines to handle the output, The idea is to remove the decision of wheter to output and what to out...
integer, parameter, public cp_p_file
integer function, public cp_print_key_should_output(iteration_info, basis_section, print_key_path, used_print_key, first_time)
returns what should be done with the given property if btest(res,cp_p_store) then the property should...
Input and persistent data for automatic RI basis optimization.
Shared numerical operations for computing the RI-RS matrix Z_lP.
subroutine, public build_gram_jacobi_blas(phi_local, n_local_grid, n_ao_used, tikhonov, d_local, d_vec_local)
Forms the conditioned dense RI-RS matrix.
subroutine, public scale_rows_by_diag(matrix, diagonal, nrow, ncol)
Multiplies every matrix row by the corresponding diagonal entry: A(l, :) <- d_l A(l,...
subroutine, public build_jacobi_diag_from_phi(phi_local, n_local_grid, n_ao_used, d_vec_local)
Computes d_l = 1/sqrt(D_ll) = 1/Σ_μ ϕ_μ(r_l)² without forming D.
subroutine, public solve_d_lp_distributed(phi_local, d_vec, d_lp, n_loc, n_ao, n_rhs, tikhonov, para_env_sub, blacs_env_sub, fm_struct_d, fm_struct_b, fm_d, fm_b, info)
Solves D Z = d with ScaLAPACK for one RI atom and replicated inputs.
subroutine, public store_z_lp_columns(mat_z_lp, z_local, local_grid_idx, n_local_grid, n_loc_ri, atom_p, r_blk_sizes, row_offset, eps_filter)
Stores dense Z_lP columns in the distributed block-sparse matrix.
Computes the RI-RS fitting matrix Z_lP.
subroutine, public compute_z_lp(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_z_lp)
Computes Z_lP for (1) a tabulated RI basis set or (2) an on-the-fly generated RI basis set.
Common setup operations used by the periodic and non-periodic GW RI-RS implementations.
subroutine, public evaluate_ao_on_points(phi, grid_points, iatom, particle_set, qs_kind_set, cell, dphi, cutoff_squared)
Evaluate contracted spherical AOs, and optionally their grid-coordinate derivatives.
Utility method to build 3-center integrals for small cell GW.
subroutine, public gw_3c_ws_create(ws, ctx)
Creates a per-thread 3c workspace: libint object + LIBXSMM contraction buffers.
subroutine, public build_3c_integral_block_ctx(int_3c, ctx, ws, atom_j, atom_k, atom_i, cell_j, cell_k, cell_i, j_offset, k_offset, i_offset, screened)
Computes the 3c integral block (mu(atom_j) nu(atom_k) | P(atom_i)) for ONE atom triple,...
subroutine, public gw_3c_ctx_release(ctx)
Releases the shared 3c-integral context.
subroutine, public gw_3c_ws_release(ws)
Releases a per-thread 3c workspace.
subroutine, public gw_3c_ctx_create(ctx, bs_env, potential_parameter, basis_j, basis_k, basis_i)
Build the shared 3c-integral context from the band-structure environment and explicitly supplied pote...
objects that represent the structure of input sections and the data contained in an input section
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
2- and 3-center electron repulsion integral routines based on libint2 Currently available operators: ...
subroutine, public eri_3center(int_abc, la_min, la_max, npgfa, zeta, rpgfa, ra, lb_min, lb_max, npgfb, zetb, rpgfb, rb, lc_min, lc_max, npgfc, zetc, rpgfc, rc, dab, dac, dbc, lib, potential_parameter, int_abc_ext)
Computes the 3-center electron repulsion integrals (ab|c) for a given set of cartesian gaussian orbit...
Machine interface based on Fortran 2003 and POSIX.
Definition machine.F:17
subroutine, public m_flush(lunit)
flushes units if the &GLOBAL flag is set accordingly
Definition machine.F:124
real(kind=dp) function, public m_walltime()
returns time from a real-time clock, protected against rolling early/easily
Definition machine.F:141
Interface to the message passing library MPI.
subroutine, public mp_mem_avail_per_rank_gb(comm, mem_avail_gb)
Memory that is currently free on the node, per MPI rank of that node, in GB.
Provides Cartesian and spherical orbital pointers and indices.
integer, dimension(:), allocatable, public ncoset
Define the data structure for the particle information.
Definition of physical constants:
Definition physcon.F:68
real(kind=dp), parameter, public angstrom
Definition physcon.F:144
subroutine, public get_qs_env(qs_env, atomic_kind_set, qs_kind_set, cell, super_cell, cell_ref, use_ref_cell, kpoints, dft_control, mos, sab_orb, sab_all, qmmm, qmmm_periodic, mimic, sac_ae, sac_ppl, sac_lri, sap_ppnl, sab_vdw, sab_scp, sap_oce, sab_lrc, sab_se, sab_xtbe, sab_tbe, sab_core, sab_xb, sab_xtb_pp, sab_xtb_nonbond, sab_almo, sab_kp, sab_kp_nosym, sab_cneo, particle_set, energy, force, matrix_h, matrix_h_im, matrix_ks, matrix_ks_im, matrix_vxc, run_rtp, rtp, matrix_h_kp, matrix_h_im_kp, matrix_ks_kp, matrix_ks_im_kp, matrix_vxc_kp, kinetic_kp, matrix_s_kp, matrix_w_kp, matrix_s_ri_aux_kp, matrix_s, matrix_s_ri_aux, matrix_w, matrix_p_mp2, matrix_p_mp2_admm, matrix_vhxc, rho, rho_xc, pw_env, ewald_env, ewald_pw, active_space, mpools, input, para_env, blacs_env, scf_control, rel_control, kinetic, qs_charges, vppl, xcint_weights, rho_core, rho_nlcc, rho_nlcc_g, ks_env, ks_qmmm_env, wf_history, scf_env, local_particles, local_molecules, distribution_2d, dbcsr_dist, molecule_kind_set, molecule_set, subsys, cp_subsys, oce, local_rho_set, rho_atom_set, task_list, task_list_soft, rho0_atom_set, rho0_mpole, rhoz_set, rhoz_cneo_set, ecoul_1c, rho0_s_rs, rho0_s_gs, rhoz_cneo_s_rs, rhoz_cneo_s_gs, do_kpoints, has_unit_metric, requires_mo_derivs, mo_derivs, mo_loc_history, nkind, natom, nelectron_total, nelectron_spin, efield, neighbor_list_id, linres_control, xas_env, virial, cp_ddapc_env, cp_ddapc_ewald, outer_scf_history, outer_scf_ihistory, x_data, et_coupling, dftb_potential, results, se_taper, se_store_int_env, se_nddo_mpole, se_nonbond_env, admm_env, lri_env, lri_density, exstate_env, ec_env, harris_env, dispersion_env, gcp_env, vee, rho_external, external_vxc, mask, mp2_env, bs_env, kg_env, wanniercentres, atprop, ls_scf_env, do_transport, transport_env, v_hartree_rspace, s_mstruct_changed, rho_changed, potential_changed, forces_up_to_date, mscfg_env, almo_scf_env, gradient_history, variable_history, embed_pot, spin_embed_pot, polar_env, mos_last_converged, eeq, rhs, do_rixs, tb_tblite)
Get the QUICKSTEP environment.
Define the quickstep kind type and their sub types.
All kind of helpful little routines.
Definition util.F:14
Provides all information about an atomic kind.
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
represent a full matrix
type of a logger, at the moment it contains just a print level starting at which level it should be l...
Shared read-only context for repeated 3-center integral block builds: screening parameters,...
Per-thread workspace for 3-center integral block builds: libint object + contraction buffers....
stores all the informations relevant to an mpi environment
Provides all information about a quickstep kind.