(git:3f0d10b)
Loading...
Searching...
No Matches
xas_tdp_integrals.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 3-center integrals machinery for the XAS_TDP method
10!> \author A. Bussy (03.2020)
11! **************************************************************************************************
14 USE coulomb_integral_interface, ONLY: coulomb_integral_context_type, coulomb_integral_init, &
15 coulomb_integral_cleanup, compute_coulomb_2c, compute_coulomb_3c, &
16 compute_coulomb_2c_derivs, compute_coulomb_3c_derivs
18 USE omp_lib, ONLY: omp_get_max_threads, &
19 omp_get_num_threads, &
20 omp_get_thread_num
27 USE cell_types, ONLY: cell_type
29 USE cp_array_utils, ONLY: cp_1d_i_p_type, &
38 USE cp_files, ONLY: close_file, &
40 USE dbt_api, ONLY: &
41 dbt_create, dbt_distribution_destroy, dbt_distribution_new, dbt_distribution_type, &
42 dbt_finalize, dbt_pgrid_create, dbt_pgrid_destroy, dbt_pgrid_type, dbt_put_block, &
43 dbt_reserve_blocks, dbt_type
48 USE eri_mme_types, ONLY: eri_mme_init, &
56 USE kinds, ONLY: dp
59 USE mathlib, ONLY: invmat_symm
60 USE message_passing, ONLY: mp_comm_type, &
63 USE orbital_pointers, ONLY: ncoset
69 USE qs_kind_types, ONLY: get_qs_kind, &
71 USE qs_neighbor_list_types, ONLY: &
91#if defined(__LIBXS)
92 USE iso_c_binding, ONLY: c_loc
93 USE libxs, ONLY: libxs_matcopy, &
94 libxs_otrans
95#endif
96#include "./base/base_uses.f90"
97
98 IMPLICIT NONE
99 PRIVATE
100
101 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'xas_tdp_integrals'
102
106
107CONTAINS
108
109! **************************************************************************************************
110!> \brief Prepares a tensor to hold 3-center integrals (pq|X), where p,q are distributed according
111!> to the given 2d dbcsr distribution of the given . The third dimension of the tensor is
112!> iteslf not distributed (i.e. the t_pgrid's third dimension has size 1). The blocks are
113!> reserved according to the neighbor lists
114!> \param pq_X the tensor to store the integrals
115!> \param ab_nl the 1st and 2nd center neighbor list
116!> \param ac_nl the 1st and 3rd center neighbor list
117!> \param matrix_dist ...
118!> \param blk_size_1 the block size in the first dimension
119!> \param blk_size_2 the block size in the second dimension
120!> \param blk_size_3 the block size in the third dimension
121!> \param only_bc_same_center only keep block if, for the corresponding integral (ab|c), b and c
122!> share the same center, i.e. r_bc = 0.0
123! **************************************************************************************************
124 SUBROUTINE create_pqx_tensor(pq_X, ab_nl, ac_nl, matrix_dist, blk_size_1, blk_size_2, &
125 blk_size_3, only_bc_same_center)
126
127 TYPE(dbt_type), INTENT(OUT) :: pq_x
128 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
129 POINTER :: ab_nl, ac_nl
130 TYPE(dbcsr_distribution_type), INTENT(IN) :: matrix_dist
131 INTEGER, DIMENSION(:), INTENT(IN) :: blk_size_1, blk_size_2, blk_size_3
132 LOGICAL, INTENT(IN), OPTIONAL :: only_bc_same_center
133
134 CHARACTER(len=*), PARAMETER :: routinen = 'create_pqX_tensor'
135
136 INTEGER :: a, b, group_handle, handle, i, iatom, &
137 ikind, jatom, katom, kkind, nblk, &
138 nblk_3, nblk_per_thread, nkind
139 INTEGER, ALLOCATABLE, DIMENSION(:) :: idx1, idx2, idx3
140 INTEGER, DIMENSION(3) :: pdims
141 INTEGER, DIMENSION(:), POINTER :: col_dist, row_dist
142 INTEGER, DIMENSION(:, :), POINTER :: mat_pgrid
143 LOGICAL :: my_sort_bc, symmetric
144 REAL(dp), DIMENSION(3) :: rab, rac, rbc
145 TYPE(dbt_distribution_type) :: t_dist
146 TYPE(dbt_pgrid_type) :: t_pgrid
147 TYPE(mp_comm_type) :: group
149 DIMENSION(:), POINTER :: ab_iter, ac_iter
150
151 NULLIFY (ab_iter, ac_iter, col_dist, row_dist, mat_pgrid)
152
153 CALL timeset(routinen, handle)
154
155 my_sort_bc = .false.
156 IF (PRESENT(only_bc_same_center)) my_sort_bc = only_bc_same_center
157
158 CALL get_neighbor_list_set_p(ab_nl, symmetric=symmetric)
159 cpassert(symmetric)
160
161 !get 2D distribution info from matrix_dist
162 CALL dbcsr_distribution_get(matrix_dist, pgrid=mat_pgrid, group=group_handle, &
163 row_dist=row_dist, col_dist=col_dist)
164 CALL group%set_handle(group_handle)
165
166 !create the corresponding tensor proc grid and dist
167 pdims(1) = SIZE(mat_pgrid, 1); pdims(2) = SIZE(mat_pgrid, 2); pdims(3) = 1
168 CALL dbt_pgrid_create(group, pdims, t_pgrid)
169
170 nblk_3 = SIZE(blk_size_3)
171 CALL dbt_distribution_new(t_dist, t_pgrid, nd_dist_1=row_dist, nd_dist_2=col_dist, &
172 nd_dist_3=[(0, i=1, nblk_3)])
173
174 !create the tensor itself.
175 CALL dbt_create(pq_x, name="(pq|X)", dist=t_dist, map1_2d=[1, 2], map2_2d=[3], &
176 blk_size_1=blk_size_1, blk_size_2=blk_size_2, blk_size_3=blk_size_3)
177
178 !count the blocks to reserve !note: dbcsr takes care of only keeping unique indices
179 CALL neighbor_list_iterator_create(ab_iter, ab_nl)
180 CALL neighbor_list_iterator_create(ac_iter, ac_nl, search=.true.)
181 nblk = 0
182 DO WHILE (neighbor_list_iterate(ab_iter) == 0)
183 CALL get_iterator_info(ab_iter, ikind=ikind, iatom=iatom, nkind=nkind, r=rab)
184
185 DO kkind = 1, nkind
186 CALL nl_set_sub_iterator(ac_iter, ikind, kkind, iatom)
187
188 DO WHILE (nl_sub_iterate(ac_iter) == 0)
189
190 IF (my_sort_bc) THEN
191 !we check for rbc or rac because of symmetry in ab_nl
192 CALL get_iterator_info(ac_iter, r=rac)
193 rbc(:) = rac(:) - rab(:)
194 IF (.NOT. (all(abs(rbc) <= 1.0e-8_dp) .OR. all(abs(rac) <= 1.0e-8_dp))) cycle
195
196 END IF
197
198 nblk = nblk + 1
199 END DO !ac_iter
200 END DO !kkind
201 END DO !ab_iter
204
205 ALLOCATE (idx1(nblk), idx2(nblk), idx3(nblk))
206
207 !actually reserve the blocks
208 CALL neighbor_list_iterator_create(ab_iter, ab_nl)
209 CALL neighbor_list_iterator_create(ac_iter, ac_nl, search=.true.)
210 nblk = 0
211 DO WHILE (neighbor_list_iterate(ab_iter) == 0)
212 CALL get_iterator_info(ab_iter, ikind=ikind, iatom=iatom, jatom=jatom, nkind=nkind, r=rab)
213
214 DO kkind = 1, nkind
215 CALL nl_set_sub_iterator(ac_iter, ikind, kkind, iatom)
216
217 DO WHILE (nl_sub_iterate(ac_iter) == 0)
218 CALL get_iterator_info(ac_iter, jatom=katom, r=rac)
219
220 IF (my_sort_bc) THEN
221 !we check for rbc or rac because of symmetry in ab_nl
222 CALL get_iterator_info(ac_iter, r=rac)
223 rbc(:) = rac(:) - rab(:)
224 IF (.NOT. (all(abs(rbc) <= 1.0e-8_dp) .OR. all(abs(rac) <= 1.0e-8_dp))) cycle
225
226 END IF
227
228 nblk = nblk + 1
229
230 idx1(nblk) = iatom
231 idx2(nblk) = jatom
232 idx3(nblk) = katom
233
234 END DO !ac_iter
235 END DO !kkind
236 END DO !ab_iter
239
240!TODO: Parallelize creation of block list.
241!$OMP PARALLEL DEFAULT(NONE) SHARED(pq_X, nblk, idx1, idx2, idx3) PRIVATE(nblk_per_thread,A,b)
242 nblk_per_thread = nblk/omp_get_num_threads() + 1
243 a = omp_get_thread_num()*nblk_per_thread + 1
244 b = min(a + nblk_per_thread, nblk)
245 CALL dbt_reserve_blocks(pq_x, idx1(a:b), idx2(a:b), idx3(a:b))
246!$OMP END PARALLEL
247 CALL dbt_finalize(pq_x)
248
249 !clean-up
250 CALL dbt_distribution_destroy(t_dist)
251 CALL dbt_pgrid_destroy(t_pgrid)
252
253 CALL timestop(handle)
254
255 END SUBROUTINE create_pqx_tensor
256
257! **************************************************************************************************
258!> \brief Fills the given 3 dimensional (pq|X) tensor with integrals
259!> \param pq_X the tensor to fill
260!> \param ab_nl the neighbor list for the first 2 centers
261!> \param ac_nl the neighbor list for the first and third centers
262!> \param basis_set_list_a basis sets for first center
263!> \param basis_set_list_b basis sets for second center
264!> \param basis_set_list_c basis sets for third center
265!> \param potential_parameter the operator for the integrals
266!> \param qs_env ...
267!> \param only_bc_same_center same as in create_pqX_tensor
268!> \param eps_screen threshold for possible screening
269!> \note The following indices are happily mixed within this routine: First center i,a,p
270!> Second center: j,b,q Third center: k,c,X
271! **************************************************************************************************
272 SUBROUTINE fill_pqx_tensor(pq_X, ab_nl, ac_nl, basis_set_list_a, basis_set_list_b, &
273 basis_set_list_c, potential_parameter, qs_env, &
274 only_bc_same_center, eps_screen)
275
276 TYPE(dbt_type) :: pq_x
277 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
278 POINTER :: ab_nl, ac_nl
279 TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER :: basis_set_list_a, basis_set_list_b, &
280 basis_set_list_c
281 TYPE(coulomb_operator_type) :: potential_parameter
282 TYPE(qs_environment_type), POINTER :: qs_env
283 LOGICAL, INTENT(IN), OPTIONAL :: only_bc_same_center
284 REAL(dp), INTENT(IN), OPTIONAL :: eps_screen
285
286 CHARACTER(len=*), PARAMETER :: routinen = 'fill_pqX_tensor'
287
288 INTEGER :: egfa, egfb, egfc, handle, i, iatom, ibasis, ikind, ilist, imax, iset, jatom, &
289 jkind, jset, katom, kkind, kset, m_max, max_nset, maxli, maxlj, maxlk, mepos, nbasis, &
290 ncoa, ncob, ncoc, ni, nj, nk, nseta, nsetb, nsetc, nthread, sgfa, sgfb, sgfc
291 INTEGER, DIMENSION(:), POINTER :: la_max, la_min, lb_max, lb_min, lc_max, &
292 lc_min, npgfa, npgfb, npgfc, nsgfa, &
293 nsgfb, nsgfc
294 INTEGER, DIMENSION(:, :), POINTER :: first_sgfa, first_sgfb, first_sgfc
295 LOGICAL :: do_screen, my_sort_bc
296 REAL(dp) :: dij, dik, djk, my_eps_screen, ri(3), &
297 rij(3), rik(3), rj(3), rjk(3), rk(3), &
298 sabc_ext, screen_radius
299 REAL(dp), ALLOCATABLE, DIMENSION(:) :: ccp_buffer, cpp_buffer
300 REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: max_contr, max_contra, max_contrb, &
301 max_contrc
302 REAL(dp), ALLOCATABLE, DIMENSION(:, :, :) :: iabc, sabc, work
303 REAL(dp), DIMENSION(:), POINTER :: set_radius_a, set_radius_b, set_radius_c
304 REAL(dp), DIMENSION(:, :), POINTER :: rpgf_a, rpgf_b, rpgf_c, zeta, zetb, zetc
305 TYPE(coulomb_integral_context_type) :: integral_context
306 TYPE(cp_2d_r_p_type), DIMENSION(:, :), POINTER :: spb, spc, tspa
307 TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER :: basis_set_list
308 TYPE(gto_basis_set_type), POINTER :: basis_set, basis_set_a, basis_set_b, &
309 basis_set_c
310 TYPE(mp_para_env_type), POINTER :: para_env
311 TYPE(o3c_container_type), POINTER :: o3c
312 TYPE(o3c_iterator_type) :: o3c_iterator
313
314 NULLIFY (basis_set, basis_set_list, para_env, la_max, la_min)
315 NULLIFY (lb_max, lb_min, lc_max, lc_min, npgfa, npgfb, npgfc, nsgfa, nsgfb, nsgfc)
316 NULLIFY (first_sgfa, first_sgfb, first_sgfc, set_radius_a, set_radius_b, set_radius_c)
317 NULLIFY (rpgf_a, rpgf_b, rpgf_c, zeta, zetb, zetc)
318 NULLIFY (basis_set_a, basis_set_b, basis_set_c, tspa, spb, spc)
319
320 CALL timeset(routinen, handle)
321
322 !Need the max l for each basis for libint (and overall max #of sets for screening)
323 nbasis = SIZE(basis_set_list_a)
324 max_nset = 0
325 maxli = 0
326 DO ibasis = 1, nbasis
327 CALL get_gto_basis_set(gto_basis_set=basis_set_list_a(ibasis)%gto_basis_set, &
328 maxl=imax, nset=iset, nsgf_set=nsgfa)
329 maxli = max(maxli, imax)
330 max_nset = max(max_nset, iset)
331 END DO
332 maxlj = 0
333 DO ibasis = 1, nbasis
334 CALL get_gto_basis_set(gto_basis_set=basis_set_list_b(ibasis)%gto_basis_set, &
335 maxl=imax, nset=iset, nsgf_set=nsgfb, npgf=npgfb)
336 maxlj = max(maxlj, imax)
337 max_nset = max(max_nset, iset)
338 END DO
339 maxlk = 0
340 DO ibasis = 1, nbasis
341 CALL get_gto_basis_set(gto_basis_set=basis_set_list_c(ibasis)%gto_basis_set, &
342 maxl=imax, nset=iset, npgf=npgfc)
343 maxlk = max(maxlk, imax)
344 max_nset = max(max_nset, iset)
345 END DO
346 m_max = maxli + maxlj + maxlk
347
348 !Screening
349 do_screen = .false.
350 IF (PRESENT(eps_screen)) THEN
351 do_screen = .true.
352 my_eps_screen = eps_screen
353 END IF
354 screen_radius = 0.0_dp
355 IF (potential_parameter%potential_type == do_potential_truncated .OR. &
356 potential_parameter%potential_type == do_potential_short) THEN
357
358 screen_radius = potential_parameter%cutoff_radius*cutoff_screen_factor
359 ELSE IF (potential_parameter%potential_type == do_potential_coulomb) THEN
360
361 screen_radius = 1000000.0_dp
362 END IF
363
364 !get maximum contraction values for abc_contract screening
365 IF (do_screen) THEN
366
367 !Allocate max_contraction arrays such that we have a specific value for each set/kind
368 ALLOCATE (max_contr(max_nset, nbasis), max_contra(max_nset, nbasis), &
369 max_contrb(max_nset, nbasis), max_contrc(max_nset, nbasis))
370
371 !Not the most elegent, but better than copying 3 times the same
372 DO ilist = 1, 3
373
374 IF (ilist == 1) basis_set_list => basis_set_list_a
375 IF (ilist == 2) basis_set_list => basis_set_list_b
376 IF (ilist == 3) basis_set_list => basis_set_list_c
377
378 max_contr = 0.0_dp
379
380 DO ibasis = 1, nbasis
381 basis_set => basis_set_list(ibasis)%gto_basis_set
382
383 DO iset = 1, basis_set%nset
384
385 ncoa = basis_set%npgf(iset)*ncoset(basis_set%lmax(iset))
386 sgfa = basis_set%first_sgf(1, iset)
387 egfa = sgfa + basis_set%nsgf_set(iset) - 1
388
389 max_contr(iset, ibasis) = &
390 maxval([(sum(abs(basis_set%sphi(1:ncoa, i))), i=sgfa, egfa)])
391
392 END DO !iset
393 END DO !ibasis
394
395 IF (ilist == 1) max_contra(:, :) = max_contr(:, :)
396 IF (ilist == 2) max_contrb(:, :) = max_contr(:, :)
397 IF (ilist == 3) max_contrc(:, :) = max_contr(:, :)
398 END DO !ilist
399 DEALLOCATE (max_contr)
400 END IF !do_screen
401
402 !To minimize memory ops in contraction, we need to pre-allocate buffers, pre-tranpose sphi_a
403 !and also trim sphi in general to have contiguous arrays
404 ALLOCATE (tspa(max_nset, nbasis), spb(max_nset, nbasis), spc(max_nset, nbasis))
405 DO ibasis = 1, nbasis
406 DO iset = 1, max_nset
407 NULLIFY (tspa(iset, ibasis)%array)
408 NULLIFY (spb(iset, ibasis)%array)
409 NULLIFY (spc(iset, ibasis)%array)
410 END DO
411 END DO
412
413 DO ilist = 1, 3
414
415 DO ibasis = 1, nbasis
416 IF (ilist == 1) basis_set => basis_set_list_a(ibasis)%gto_basis_set
417 IF (ilist == 2) basis_set => basis_set_list_b(ibasis)%gto_basis_set
418 IF (ilist == 3) basis_set => basis_set_list_c(ibasis)%gto_basis_set
419
420 DO iset = 1, basis_set%nset
421
422 ncoa = basis_set%npgf(iset)*ncoset(basis_set%lmax(iset))
423 sgfa = basis_set%first_sgf(1, iset)
424 egfa = sgfa + basis_set%nsgf_set(iset) - 1
425
426 IF (ilist == 1) THEN
427 ALLOCATE (tspa(iset, ibasis)%array(basis_set%nsgf_set(iset), ncoa))
428#if defined(__LIBXS)
429 CALL libxs_otrans(c_loc(tspa(iset, ibasis)%array), &
430 c_loc(basis_set%sphi(1, sgfa)), &
431 8, ncoa, egfa - sgfa + 1, &
432 SIZE(basis_set%sphi, 1), &
433 basis_set%nsgf_set(iset))
434#else
435 tspa(iset, ibasis)%array(:, :) = transpose(basis_set%sphi(1:ncoa, sgfa:egfa))
436#endif
437 ELSE IF (ilist == 2) THEN
438 ALLOCATE (spb(iset, ibasis)%array(ncoa, basis_set%nsgf_set(iset)))
439#if defined(__LIBXS)
440 CALL libxs_matcopy(c_loc(spb(iset, ibasis)%array), &
441 c_loc(basis_set%sphi(1, sgfa)), &
442 8, ncoa, egfa - sgfa + 1, &
443 SIZE(basis_set%sphi, 1), ncoa)
444#else
445 spb(iset, ibasis)%array(:, :) = basis_set%sphi(1:ncoa, sgfa:egfa)
446#endif
447 ELSE
448 ALLOCATE (spc(iset, ibasis)%array(ncoa, basis_set%nsgf_set(iset)))
449#if defined(__LIBXS)
450 CALL libxs_matcopy(c_loc(spc(iset, ibasis)%array), &
451 c_loc(basis_set%sphi(1, sgfa)), &
452 8, ncoa, egfa - sgfa + 1, &
453 SIZE(basis_set%sphi, 1), ncoa)
454#else
455 spc(iset, ibasis)%array(:, :) = basis_set%sphi(1:ncoa, sgfa:egfa)
456#endif
457 END IF
458
459 END DO !iset
460 END DO !ibasis
461 END DO !ilist
462
463 my_sort_bc = .false.
464 IF (PRESENT(only_bc_same_center)) my_sort_bc = only_bc_same_center
465
466 CALL get_qs_env(qs_env, para_env=para_env)
467 CALL r12_fundamentals_init(m_max, potential_parameter, para_env)
468
469 !Strategy: we use the o3c iterator because it is OMP parallelized and also takes the
470 ! only_bc_same_center argument. Only the dbcsr_put_block is critical
471
472 nthread = 1
473!$ nthread = omp_get_max_threads()
474
475 ALLOCATE (o3c)
476 CALL init_o3c_container(o3c, 1, basis_set_list_a, basis_set_list_b, basis_set_list_c, &
477 ab_nl, ac_nl, only_bc_same_center=my_sort_bc)
478 CALL o3c_iterator_create(o3c, o3c_iterator, nthread=nthread)
479
480!$OMP PARALLEL DEFAULT(NONE) &
481!$OMP SHARED (pq_X,do_screen,max_nset,basis_set_list_a,max_contra,max_contrb,max_contrc,&
482!$OMP basis_set_list_b, basis_set_list_c,ncoset,screen_radius,potential_parameter,&
483!$OMP my_eps_screen,maxli,maxlj,maxlk,my_sort_bc,nthread,o3c,o3c_iterator,tspa,spb,spc) &
484!$OMP PRIVATE (integral_context,i,mepos,work,iset,ncoa,sgfa,egfa,nseta,iatom,ikind,jatom,jkind,katom,kkind,&
485!$OMP rij,rik,rjk,basis_set_a,nsetb,la_max,la_min,lb_max,lb_min,lc_max,lc_min,npgfa,&
486!$OMP npgfb,npgfc,nsgfa,nsgfb,nsgfc,ri,rk,first_sgfa,first_sgfb,first_sgfc,nsetc,&
487!$OMP set_radius_a,set_radius_b,set_radius_c,rj,rpgf_a,rpgf_b,rpgf_c,zeta,zetb,&
488!$OMP zetc,basis_set_b,basis_set_c,dij,dik,djk,ni,nj,nk,iabc,sabc,jset,kset,&
489!$OMP ncob,ncoc,sgfb,sgfc,egfb,egfc,sabc_ext,cpp_buffer,ccp_buffer)
490
491 mepos = 0
492!$ mepos = omp_get_thread_num()
493
494 !each thread need its own libint object (internals may change at different rates)
495 integral_context = coulomb_integral_context_type()
496 CALL coulomb_integral_init(integral_context, max_am_3c=max(maxli, maxlj, maxlk), &
497 derivative_order=0, library=library_libint)
498
499 DO WHILE (o3c_iterate(o3c_iterator, mepos=mepos) == 0)
500 CALL get_o3c_iterator_info(o3c_iterator, mepos=mepos, ikind=ikind, jkind=jkind, kkind=kkind, &
501 iatom=iatom, jatom=jatom, katom=katom, rij=rij, rik=rik)
502
503 !get first center basis info
504 basis_set_a => basis_set_list_a(ikind)%gto_basis_set
505 first_sgfa => basis_set_a%first_sgf
506 la_max => basis_set_a%lmax
507 la_min => basis_set_a%lmin
508 npgfa => basis_set_a%npgf
509 nseta = basis_set_a%nset
510 nsgfa => basis_set_a%nsgf_set
511 zeta => basis_set_a%zet
512 rpgf_a => basis_set_a%pgf_radius
513 set_radius_a => basis_set_a%set_radius
514 ni = sum(nsgfa)
515 !second center basis info
516 basis_set_b => basis_set_list_b(jkind)%gto_basis_set
517 first_sgfb => basis_set_b%first_sgf
518 lb_max => basis_set_b%lmax
519 lb_min => basis_set_b%lmin
520 npgfb => basis_set_b%npgf
521 nsetb = basis_set_b%nset
522 nsgfb => basis_set_b%nsgf_set
523 zetb => basis_set_b%zet
524 rpgf_b => basis_set_b%pgf_radius
525 set_radius_b => basis_set_b%set_radius
526 nj = sum(nsgfb)
527 !third center basis info
528 basis_set_c => basis_set_list_c(kkind)%gto_basis_set
529 first_sgfc => basis_set_c%first_sgf
530 lc_max => basis_set_c%lmax
531 lc_min => basis_set_c%lmin
532 npgfc => basis_set_c%npgf
533 nsetc = basis_set_c%nset
534 nsgfc => basis_set_c%nsgf_set
535 zetc => basis_set_c%zet
536 rpgf_c => basis_set_c%pgf_radius
537 set_radius_c => basis_set_c%set_radius
538 nk = sum(nsgfc)
539
540 !position and distances, only relative pos matter for libint
541 rjk = rik - rij
542 ri = 0.0_dp
543 rj = rij ! ri + rij
544 rk = rik ! ri + rik
545
546 djk = norm2(rjk)
547 dij = norm2(rij)
548 dik = norm2(rik)
549
550 !sgf integrals
551 ALLOCATE (iabc(ni, nj, nk))
552 iabc(:, :, :) = 0.0_dp
553
554 DO iset = 1, nseta
555 ncoa = npgfa(iset)*ncoset(la_max(iset))
556 sgfa = first_sgfa(1, iset)
557 egfa = sgfa + nsgfa(iset) - 1
558
559 DO jset = 1, nsetb
560 ncob = npgfb(jset)*ncoset(lb_max(jset))
561 sgfb = first_sgfb(1, jset)
562 egfb = sgfb + nsgfb(jset) - 1
563
564 !screening (overlap)
565 IF (set_radius_a(iset) + set_radius_b(jset) < dij) cycle
566
567 DO kset = 1, nsetc
568 ncoc = npgfc(kset)*ncoset(lc_max(kset))
569 sgfc = first_sgfc(1, kset)
570 egfc = sgfc + nsgfc(kset) - 1
571
572 !screening (potential)
573 IF (set_radius_a(iset) + set_radius_c(kset) + screen_radius < dik) cycle
574 IF (set_radius_b(jset) + set_radius_c(kset) + screen_radius < djk) cycle
575
576 !pgf integrals
577 ALLOCATE (sabc(ncoa, ncob, ncoc))
578 sabc(:, :, :) = 0.0_dp
579
580 IF (do_screen) THEN
581 CALL compute_coulomb_3c(integral_context, la_min(iset), la_max(iset), lb_min(jset), &
582 lb_max(jset), lc_min(kset), lc_max(kset), npgfa(iset), npgfb(jset), npgfc(kset), &
583 zeta(:, iset), zetb(:, jset), zetc(:, kset), rpgf_a(:, iset), rpgf_b(:, jset), &
584 rpgf_c(:, kset), ri, rj, rk, sabc, potential_parameter, dab=dij, dac=dik, dbc=djk, &
585 int_abc_ext=sabc_ext)
586 IF (my_eps_screen > sabc_ext*(max_contra(iset, ikind)* &
587 max_contrb(jset, jkind)* &
588 max_contrc(kset, kkind))) THEN
589 DEALLOCATE (sabc)
590 cycle
591 END IF
592 ELSE
593 CALL compute_coulomb_3c(integral_context, la_min(iset), la_max(iset), lb_min(jset), &
594 lb_max(jset), lc_min(kset), lc_max(kset), npgfa(iset), npgfb(jset), npgfc(kset), &
595 zeta(:, iset), zetb(:, jset), zetc(:, kset), rpgf_a(:, iset), rpgf_b(:, jset), &
596 rpgf_c(:, kset), ri, rj, rk, sabc, potential_parameter, dab=dij, dac=dik, dbc=djk)
597 END IF
598
599 ALLOCATE (work(nsgfa(iset), nsgfb(jset), nsgfc(kset)))
600
601 CALL abc_contract_xsmm(work, sabc, tspa(iset, ikind)%array, spb(jset, jkind)%array, &
602 spc(kset, kkind)%array, ncoa, ncob, ncoc, nsgfa(iset), &
603 nsgfb(jset), nsgfc(kset), cpp_buffer, ccp_buffer)
604
605 iabc(sgfa:egfa, sgfb:egfb, sgfc:egfc) = work(:, :, :)
606 DEALLOCATE (sabc, work)
607
608 END DO !kset
609 END DO !jset
610 END DO !iset
611
612 !Add the integral to the proper tensor block
613!$OMP CRITICAL(omp_fill_pqX_tensor)
614 CALL dbt_put_block(pq_x, [iatom, jatom, katom], shape(iabc), iabc, summation=.true.)
615!$OMP END CRITICAL(omp_fill_pqX_tensor)
616
617 DEALLOCATE (iabc)
618 END DO !o3c_iterator
619
620 IF (ALLOCATED(ccp_buffer)) DEALLOCATE (ccp_buffer)
621 IF (ALLOCATED(cpp_buffer)) DEALLOCATE (cpp_buffer)
622
623 CALL coulomb_integral_cleanup(integral_context)
624
625!$OMP END PARALLEL
626 CALL o3c_iterator_release(o3c_iterator)
627 CALL release_o3c_container(o3c)
628 DEALLOCATE (o3c)
629
630 DO iset = 1, max_nset
631 DO ibasis = 1, nbasis
632 IF (ASSOCIATED(tspa(iset, ibasis)%array)) DEALLOCATE (tspa(iset, ibasis)%array)
633 IF (ASSOCIATED(spb(iset, ibasis)%array)) DEALLOCATE (spb(iset, ibasis)%array)
634 IF (ASSOCIATED(spc(iset, ibasis)%array)) DEALLOCATE (spc(iset, ibasis)%array)
635 END DO
636 END DO
637 DEALLOCATE (tspa, spb, spc)
638
639 CALL timestop(handle)
640
641 END SUBROUTINE fill_pqx_tensor
642
643! **************************************************************************************************
644!> \brief Builds a neighbor lists set for overlaping 2-center S_ab, where b is restricted on a
645!> a given list of atoms. Used for Coulomb RI where (aI|P) = sum_b C_bI (ab|P), where
646!> contraction coeff C_bI is assumed to be non-zero only on excited atoms
647!> \param ab_list the neighbor list
648!> \param basis_a basis set list for atom a
649!> \param basis_b basis set list for atom b
650!> \param qs_env ...
651!> \param excited_atoms the indices of the excited atoms on which b is centered
652!> \param ext_dist2d use an external distribution2d
653! **************************************************************************************************
654 SUBROUTINE build_xas_tdp_ovlp_nl(ab_list, basis_a, basis_b, qs_env, excited_atoms, ext_dist2d)
655
656 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
657 POINTER :: ab_list
658 TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER :: basis_a, basis_b
659 TYPE(qs_environment_type), POINTER :: qs_env
660 INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: excited_atoms
661 TYPE(distribution_2d_type), OPTIONAL, POINTER :: ext_dist2d
662
663 INTEGER :: ikind, nkind
664 LOGICAL :: my_restrictb
665 LOGICAL, ALLOCATABLE, DIMENSION(:) :: a_present, b_present
666 REAL(dp) :: subcells
667 REAL(dp), ALLOCATABLE, DIMENSION(:) :: a_radius, b_radius
668 REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: pair_radius
669 TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
670 TYPE(cell_type), POINTER :: cell
671 TYPE(distribution_1d_type), POINTER :: distribution_1d
672 TYPE(distribution_2d_type), POINTER :: distribution_2d
673 TYPE(local_atoms_type), ALLOCATABLE, DIMENSION(:) :: atom2d
674 TYPE(molecule_type), DIMENSION(:), POINTER :: molecule_set
675 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
676
677 NULLIFY (atomic_kind_set, distribution_1d, distribution_2d, molecule_set, particle_set, cell)
678
679! Initialization
680 CALL get_qs_env(qs_env, nkind=nkind)
681 CALL section_vals_val_get(qs_env%input, "DFT%SUBCELLS", r_val=subcells)
682
683 my_restrictb = .false.
684 IF (PRESENT(excited_atoms)) THEN
685 my_restrictb = .true.
686 END IF
687
688 ALLOCATE (a_present(nkind), b_present(nkind))
689 a_present = .false.
690 b_present = .false.
691 ALLOCATE (a_radius(nkind), b_radius(nkind))
692 a_radius = 0.0_dp
693 b_radius = 0.0_dp
694
695! Set up the radii
696 DO ikind = 1, nkind
697 IF (ASSOCIATED(basis_a(ikind)%gto_basis_set)) THEN
698 a_present(ikind) = .true.
699 CALL get_gto_basis_set(basis_a(ikind)%gto_basis_set, kind_radius=a_radius(ikind))
700 END IF
701
702 IF (ASSOCIATED(basis_b(ikind)%gto_basis_set)) THEN
703 b_present(ikind) = .true.
704 CALL get_gto_basis_set(basis_b(ikind)%gto_basis_set, kind_radius=b_radius(ikind))
705 END IF
706 END DO !ikind
707
708 ALLOCATE (pair_radius(nkind, nkind))
709 pair_radius = 0.0_dp
710 CALL pair_radius_setup(a_present, b_present, a_radius, b_radius, pair_radius)
711
712! Set up the nl
713 CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, cell=cell, &
714 distribution_2d=distribution_2d, local_particles=distribution_1d, &
715 particle_set=particle_set, molecule_set=molecule_set)
716
717 !use an external distribution_2d if required
718 IF (PRESENT(ext_dist2d)) distribution_2d => ext_dist2d
719
720 ALLOCATE (atom2d(nkind))
721 CALL atom2d_build(atom2d, distribution_1d, distribution_2d, atomic_kind_set, &
722 molecule_set, .false., particle_set)
723
724 IF (my_restrictb) THEN
725
726 CALL build_neighbor_lists(ab_list, particle_set, atom2d, cell, pair_radius, subcells, &
727 atomb_to_keep=excited_atoms, nlname="XAS_TDP_ovlp_nl")
728
729 ELSE
730
731 CALL build_neighbor_lists(ab_list, particle_set, atom2d, cell, pair_radius, subcells, &
732 nlname="XAS_TDP_ovlp_nl")
733
734 END IF
735! Clean-up
736 CALL atom2d_cleanup(atom2d)
737
738 END SUBROUTINE build_xas_tdp_ovlp_nl
739
740! **************************************************************************************************
741!> \brief Builds a neighbor lists set taylored for 3-center integral within XAS TDP, such that only
742!> excited atoms are taken into account for the list_c
743!> \param ac_list the neighbor list ready for 3-center integrals
744!> \param basis_a basis set list for atom a
745!> \param basis_c basis set list for atom c
746!> \param op_type to indicate whther the list should be built with overlap, Coulomb or else in mind
747!> \param qs_env ...
748!> \param excited_atoms the indices of the excited atoms to consider (if not given, all atoms are taken)
749!> \param x_range in case some truncated/screened operator is used, gives its range
750!> \param ext_dist2d external distribution_2d to be used
751!> \note Based on setup_neighbor_list with added features
752! **************************************************************************************************
753 SUBROUTINE build_xas_tdp_3c_nl(ac_list, basis_a, basis_c, op_type, qs_env, excited_atoms, &
754 x_range, ext_dist2d)
755
756 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
757 POINTER :: ac_list
758 TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER :: basis_a, basis_c
759 INTEGER, INTENT(IN) :: op_type
760 TYPE(qs_environment_type), POINTER :: qs_env
761 INTEGER, DIMENSION(:), INTENT(IN), OPTIONAL :: excited_atoms
762 REAL(dp), INTENT(IN), OPTIONAL :: x_range
763 TYPE(distribution_2d_type), OPTIONAL, POINTER :: ext_dist2d
764
765 INTEGER :: ikind, nkind
766 LOGICAL :: sort_atoms
767 LOGICAL, ALLOCATABLE, DIMENSION(:) :: a_present, c_present
768 REAL(dp) :: subcells
769 REAL(dp), ALLOCATABLE, DIMENSION(:) :: a_radius, c_radius
770 REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: pair_radius
771 TYPE(atomic_kind_type), DIMENSION(:), POINTER :: atomic_kind_set
772 TYPE(cell_type), POINTER :: cell
773 TYPE(distribution_1d_type), POINTER :: distribution_1d
774 TYPE(distribution_2d_type), POINTER :: distribution_2d
775 TYPE(local_atoms_type), ALLOCATABLE, DIMENSION(:) :: atom2d
776 TYPE(molecule_type), DIMENSION(:), POINTER :: molecule_set
777 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
778
779 NULLIFY (atomic_kind_set, distribution_1d, distribution_2d, molecule_set, particle_set, cell)
780
781! Initialization
782 CALL get_qs_env(qs_env, nkind=nkind)
783 CALL section_vals_val_get(qs_env%input, "DFT%SUBCELLS", r_val=subcells)
784 sort_atoms = .false.
785 IF ((PRESENT(excited_atoms))) sort_atoms = .true.
786
787 ALLOCATE (a_present(nkind), c_present(nkind))
788 a_present = .false.
789 c_present = .false.
790 ALLOCATE (a_radius(nkind), c_radius(nkind))
791 a_radius = 0.0_dp
792 c_radius = 0.0_dp
793
794! Set up the radii, depending on the operator type
795 IF (op_type == do_potential_id) THEN
796
797 !overlap => use the kind radius for both a and c
798 DO ikind = 1, nkind
799 !orbital basis set
800 IF (ASSOCIATED(basis_a(ikind)%gto_basis_set)) THEN
801 a_present(ikind) = .true.
802 CALL get_gto_basis_set(basis_a(ikind)%gto_basis_set, kind_radius=a_radius(ikind))
803 END IF
804 !RI_XAS basis set
805 IF (ASSOCIATED(basis_c(ikind)%gto_basis_set)) THEN
806 c_present(ikind) = .true.
807 CALL get_gto_basis_set(basis_c(ikind)%gto_basis_set, kind_radius=c_radius(ikind))
808 END IF
809 END DO !ikind
810
811 ELSE IF (op_type == do_potential_coulomb) THEN
812
813 !Coulomb operator, virtually infinite range => set c_radius to arbitrarily large number
814 DO ikind = 1, nkind
815 IF (ASSOCIATED(basis_c(ikind)%gto_basis_set)) THEN
816 c_present(ikind) = .true.
817 c_radius(ikind) = 1000000.0_dp
818 END IF
819 IF (ASSOCIATED(basis_a(ikind)%gto_basis_set)) a_present(ikind) = .true.
820 END DO !ikind
821
822 ELSE IF (op_type == do_potential_truncated .OR. op_type == do_potential_short) THEN
823
824 !Truncated coulomb/short range: set c_radius to x_range + the kind_radii
825 DO ikind = 1, nkind
826 IF (ASSOCIATED(basis_a(ikind)%gto_basis_set)) THEN
827 a_present(ikind) = .true.
828 CALL get_gto_basis_set(basis_a(ikind)%gto_basis_set, kind_radius=a_radius(ikind))
829 END IF
830 IF (ASSOCIATED(basis_c(ikind)%gto_basis_set)) THEN
831 c_present(ikind) = .true.
832 CALL get_gto_basis_set(basis_c(ikind)%gto_basis_set, kind_radius=c_radius(ikind))
833 c_radius(ikind) = c_radius(ikind) + x_range
834 END IF
835 END DO !ikind
836
837 ELSE
838 cpabort("Operator not known")
839 END IF
840
841 ALLOCATE (pair_radius(nkind, nkind))
842 pair_radius = 0.0_dp
843 CALL pair_radius_setup(a_present, c_present, a_radius, c_radius, pair_radius)
844
845! Actually setup the list
846 CALL get_qs_env(qs_env, atomic_kind_set=atomic_kind_set, cell=cell, &
847 distribution_2d=distribution_2d, local_particles=distribution_1d, &
848 particle_set=particle_set, molecule_set=molecule_set)
849
850 !use an external distribution_2d if required
851 IF (PRESENT(ext_dist2d)) distribution_2d => ext_dist2d
852
853 ALLOCATE (atom2d(nkind))
854 CALL atom2d_build(atom2d, distribution_1d, distribution_2d, atomic_kind_set, &
855 molecule_set, .false., particle_set)
856
857 IF (sort_atoms) THEN
858 CALL build_neighbor_lists(ac_list, particle_set, atom2d, cell, pair_radius, subcells, &
859 operator_type="ABC", atomb_to_keep=excited_atoms, &
860 nlname="XAS_TDP_3c_nl")
861 ELSE
862 CALL build_neighbor_lists(ac_list, particle_set, atom2d, cell, pair_radius, subcells, &
863 operator_type="ABC", nlname="XAS_TDP_3c_nl")
864 END IF
865
866! Clean-up
867 CALL atom2d_cleanup(atom2d)
868
869 END SUBROUTINE build_xas_tdp_3c_nl
870
871! **************************************************************************************************
872!> \brief Returns an optimized distribution_2d for the given neighbor lists based on an evaluation
873!> of the cost of the corresponding 3-center integrals
874!> \param opt_3c_dist2d the optimized distribution_2d
875!> \param ab_list ...
876!> \param ac_list ...
877!> \param basis_set_a ...
878!> \param basis_set_b ...
879!> \param basis_set_c ...
880!> \param qs_env ...
881!> \param only_bc_same_center ...
882! **************************************************************************************************
883 SUBROUTINE get_opt_3c_dist2d(opt_3c_dist2d, ab_list, ac_list, basis_set_a, basis_set_b, &
884 basis_set_c, qs_env, only_bc_same_center)
885
886 TYPE(distribution_2d_type), POINTER :: opt_3c_dist2d
887 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
888 POINTER :: ab_list, ac_list
889 TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER :: basis_set_a, basis_set_b, basis_set_c
890 TYPE(qs_environment_type), POINTER :: qs_env
891 LOGICAL, INTENT(IN), OPTIONAL :: only_bc_same_center
892
893 CHARACTER(len=*), PARAMETER :: routinen = 'get_opt_3c_dist2d'
894
895 INTEGER :: handle, i, iatom, ikind, ip, jatom, &
896 jkind, kkind, mypcol, myprow, n, &
897 natom, nkind, npcol, nprow, nsgfa, &
898 nsgfb, nsgfc
899 INTEGER, ALLOCATABLE, DIMENSION(:) :: nparticle_local_col, nparticle_local_row
900 INTEGER, DIMENSION(:, :), POINTER :: col_dist, row_dist
901 LOGICAL :: my_sort_bc
902 REAL(dp) :: cost, rab(3), rac(3), rbc(3)
903 REAL(dp), ALLOCATABLE, DIMENSION(:) :: col_cost, col_proc_cost, row_cost, &
904 row_proc_cost
905 TYPE(cp_1d_i_p_type), DIMENSION(:), POINTER :: local_particle_col, local_particle_row
906 TYPE(cp_blacs_env_type), POINTER :: blacs_env
907 TYPE(mp_para_env_type), POINTER :: para_env
909 DIMENSION(:), POINTER :: ab_iter, ac_iter
910 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
911 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
912
913 NULLIFY (para_env, col_dist, row_dist, blacs_env, qs_kind_set, particle_set)
914 NULLIFY (local_particle_col, local_particle_row, ab_iter, ac_iter)
915
916 CALL timeset(routinen, handle)
917
918 !Idea: create a,b and a,c nl_iterators in the original dist, then loop over them and compute the
919 ! cost of each ab pairs and project on the col/row. Then distribute the atom col/row to
920 ! the proc col/row in order to spread out the cost as much as possible
921
922 my_sort_bc = .false.
923 IF (PRESENT(only_bc_same_center)) my_sort_bc = only_bc_same_center
924
925 CALL get_qs_env(qs_env, natom=natom, para_env=para_env, blacs_env=blacs_env, &
926 qs_kind_set=qs_kind_set, particle_set=particle_set, nkind=nkind)
927
928 myprow = blacs_env%mepos(1) + 1
929 mypcol = blacs_env%mepos(2) + 1
930 nprow = blacs_env%num_pe(1)
931 npcol = blacs_env%num_pe(2)
932
933 ALLOCATE (col_cost(natom), row_cost(natom))
934 col_cost = 0.0_dp; row_cost = 0.0_dp
935
936 ALLOCATE (row_dist(natom, 2), col_dist(natom, 2))
937 row_dist = 1; col_dist = 1
938
939 CALL neighbor_list_iterator_create(ab_iter, ab_list)
940 CALL neighbor_list_iterator_create(ac_iter, ac_list, search=.true.)
941 DO WHILE (neighbor_list_iterate(ab_iter) == 0)
942 CALL get_iterator_info(ab_iter, ikind=ikind, jkind=jkind, iatom=iatom, jatom=jatom, r=rab)
943
944 DO kkind = 1, nkind
945 CALL nl_set_sub_iterator(ac_iter, ikind, kkind, iatom)
946
947 DO WHILE (nl_sub_iterate(ac_iter) == 0)
948
949 IF (my_sort_bc) THEN
950 !only take a,b,c if b,c (or a,c because of symmetry) share the same center
951 CALL get_iterator_info(ac_iter, r=rac)
952 rbc(:) = rac(:) - rab(:)
953 IF (.NOT. (all(abs(rbc) <= 1.0e-8_dp) .OR. all(abs(rac) <= 1.0e-8_dp))) cycle
954
955 END IF
956
957 !Use the size of integral as measure as contraciton cost seems to dominate
958 nsgfa = basis_set_a(ikind)%gto_basis_set%nsgf
959 nsgfb = basis_set_b(jkind)%gto_basis_set%nsgf
960 nsgfc = basis_set_c(kkind)%gto_basis_set%nsgf
961
962 cost = real(nsgfa*nsgfb*nsgfc, dp)
963
964 row_cost(iatom) = row_cost(iatom) + cost
965 col_cost(jatom) = col_cost(jatom) + cost
966
967 END DO !ac_iter
968 END DO !kkind
969 END DO !ab_iter
972
973 CALL para_env%sum(row_cost)
974 CALL para_env%sum(col_cost)
975
976 !Distribute the cost as evenly as possible
977 ALLOCATE (col_proc_cost(npcol), row_proc_cost(nprow))
978 col_proc_cost = 0.0_dp; row_proc_cost = 0.0_dp
979 DO i = 1, natom
980 iatom = maxloc(row_cost, 1)
981 ip = minloc(row_proc_cost, 1)
982 row_proc_cost(ip) = row_proc_cost(ip) + row_cost(iatom)
983 row_dist(iatom, 1) = ip
984 row_cost(iatom) = 0.0_dp
985
986 iatom = maxloc(col_cost, 1)
987 ip = minloc(col_proc_cost, 1)
988 col_proc_cost(ip) = col_proc_cost(ip) + col_cost(iatom)
989 col_dist(iatom, 1) = ip
990 col_cost(iatom) = 0.0_dp
991 END DO
992
993 !the usual stuff
994 ALLOCATE (local_particle_col(nkind), local_particle_row(nkind))
995 ALLOCATE (nparticle_local_row(nkind), nparticle_local_col(nkind))
996 nparticle_local_row = 0; nparticle_local_col = 0
997
998 DO iatom = 1, natom
999 ikind = particle_set(iatom)%atomic_kind%kind_number
1000
1001 IF (row_dist(iatom, 1) == myprow) nparticle_local_row(ikind) = nparticle_local_row(ikind) + 1
1002 IF (col_dist(iatom, 1) == mypcol) nparticle_local_col(ikind) = nparticle_local_col(ikind) + 1
1003 END DO
1004
1005 DO ikind = 1, nkind
1006 n = nparticle_local_row(ikind)
1007 ALLOCATE (local_particle_row(ikind)%array(n))
1008
1009 n = nparticle_local_col(ikind)
1010 ALLOCATE (local_particle_col(ikind)%array(n))
1011 END DO
1012
1013 nparticle_local_row = 0; nparticle_local_col = 0
1014 DO iatom = 1, natom
1015 ikind = particle_set(iatom)%atomic_kind%kind_number
1016
1017 IF (row_dist(iatom, 1) == myprow) THEN
1018 nparticle_local_row(ikind) = nparticle_local_row(ikind) + 1
1019 local_particle_row(ikind)%array(nparticle_local_row(ikind)) = iatom
1020 END IF
1021 IF (col_dist(iatom, 1) == mypcol) THEN
1022 nparticle_local_col(ikind) = nparticle_local_col(ikind) + 1
1023 local_particle_col(ikind)%array(nparticle_local_col(ikind)) = iatom
1024 END IF
1025 END DO
1026
1027 !Finally create the dist_2d
1028 row_dist(:, 1) = row_dist(:, 1) - 1
1029 col_dist(:, 1) = col_dist(:, 1) - 1
1030 CALL distribution_2d_create(opt_3c_dist2d, row_distribution_ptr=row_dist, &
1031 col_distribution_ptr=col_dist, local_rows_ptr=local_particle_row, &
1032 local_cols_ptr=local_particle_col, blacs_env=blacs_env)
1033
1034 CALL timestop(handle)
1035
1036 END SUBROUTINE get_opt_3c_dist2d
1037
1038! **************************************************************************************************
1039!> \brief Computes the RI exchange 3-center integrals (ab|c), where c is from the RI_XAS basis and
1040!> centered on excited atoms and kind. The operator used is that of the RI metric
1041!> \param ex_atoms excited atoms on which the third center is located
1042!> \param xas_tdp_env ...
1043!> \param xas_tdp_control ...
1044!> \param qs_env ...
1045!> \note This routine is called once for each excited atom. Because there are many different a,b
1046!> pairs involved, load balance is ok. This allows memory saving
1047! **************************************************************************************************
1048 SUBROUTINE compute_ri_3c_exchange(ex_atoms, xas_tdp_env, xas_tdp_control, qs_env)
1049
1050 INTEGER, DIMENSION(:), INTENT(IN) :: ex_atoms
1051 TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1052 TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1053 TYPE(qs_environment_type), POINTER :: qs_env
1054
1055 CHARACTER(len=*), PARAMETER :: routinen = 'compute_ri_3c_exchange'
1056
1057 INTEGER :: handle, natom, nkind
1058 INTEGER, ALLOCATABLE, DIMENSION(:) :: blk_size_orb, blk_size_ri
1059 TYPE(dbcsr_distribution_type) :: opt_dbcsr_dist
1060 TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER :: basis_set_orb, basis_set_ri
1061 TYPE(mp_para_env_type), POINTER :: para_env
1062 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
1063 POINTER :: ab_list, ac_list
1064 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1065 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1066
1067 NULLIFY (basis_set_ri, basis_set_orb, ac_list, ab_list, qs_kind_set, para_env, particle_set)
1068
1069 CALL timeset(routinen, handle)
1070
1071! Take what we need from the qs_env
1072 CALL get_qs_env(qs_env, nkind=nkind, qs_kind_set=qs_kind_set, para_env=para_env, &
1073 natom=natom, particle_set=particle_set)
1074
1075! Build the basis set lists
1076 ALLOCATE (basis_set_ri(nkind))
1077 ALLOCATE (basis_set_orb(nkind))
1078 CALL basis_set_list_setup(basis_set_ri, "RI_XAS", qs_kind_set)
1079 CALL basis_set_list_setup(basis_set_orb, "ORB", qs_kind_set)
1080
1081! Get the optimized distribution 2d for theses integrals (and store it in xas_tdp_env)
1082 CALL build_xas_tdp_ovlp_nl(ab_list, basis_set_orb, basis_set_orb, qs_env)
1083 CALL build_xas_tdp_3c_nl(ac_list, basis_set_orb, basis_set_ri, &
1084 xas_tdp_control%ri_m_potential%potential_type, qs_env, &
1085 excited_atoms=ex_atoms, x_range=xas_tdp_control%ri_m_potential%cutoff_radius)
1086
1087 CALL get_opt_3c_dist2d(xas_tdp_env%opt_dist2d_ex, ab_list, ac_list, basis_set_orb, &
1088 basis_set_orb, basis_set_ri, qs_env)
1089 CALL release_neighbor_list_sets(ab_list)
1090 CALL release_neighbor_list_sets(ac_list)
1091
1092! Build the ab and ac centers neighbor lists based on the optimized distribution
1093 CALL build_xas_tdp_ovlp_nl(ab_list, basis_set_orb, basis_set_orb, qs_env, &
1094 ext_dist2d=xas_tdp_env%opt_dist2d_ex)
1095 CALL build_xas_tdp_3c_nl(ac_list, basis_set_orb, basis_set_ri, &
1096 xas_tdp_control%ri_m_potential%potential_type, qs_env, &
1097 excited_atoms=ex_atoms, x_range=xas_tdp_control%ri_m_potential%cutoff_radius, &
1098 ext_dist2d=xas_tdp_env%opt_dist2d_ex)
1099
1100! Allocate, init and compute the integrals.
1101 ALLOCATE (blk_size_orb(natom), blk_size_ri(natom))
1102 CALL cp_dbcsr_dist2d_to_dist(xas_tdp_env%opt_dist2d_ex, opt_dbcsr_dist)
1103 CALL get_particle_set(particle_set, qs_kind_set, nsgf=blk_size_orb, basis=basis_set_orb)
1104 CALL get_particle_set(particle_set, qs_kind_set, nsgf=blk_size_ri, basis=basis_set_ri)
1105
1106 ALLOCATE (xas_tdp_env%ri_3c_ex)
1107 CALL create_pqx_tensor(xas_tdp_env%ri_3c_ex, ab_list, ac_list, opt_dbcsr_dist, blk_size_orb, &
1108 blk_size_orb, blk_size_ri)
1109 CALL fill_pqx_tensor(xas_tdp_env%ri_3c_ex, ab_list, ac_list, basis_set_orb, basis_set_orb, &
1110 basis_set_ri, xas_tdp_control%ri_m_potential, qs_env, &
1111 eps_screen=xas_tdp_control%eps_screen)
1112
1113! Clean-up
1114 CALL release_neighbor_list_sets(ab_list)
1115 CALL release_neighbor_list_sets(ac_list)
1116 CALL dbcsr_distribution_release(opt_dbcsr_dist)
1117 DEALLOCATE (basis_set_ri, basis_set_orb)
1118
1119 !not strictly necessary but avoid having any load unbalance here being reported in the
1120 !timings for other routines
1121 CALL para_env%sync()
1122
1123 CALL timestop(handle)
1124
1125 END SUBROUTINE compute_ri_3c_exchange
1126
1127! **************************************************************************************************
1128!> \brief Computes the RI Coulomb 3-center integrals (ab|c), where c is from the RI_XAS basis and
1129!> centered on the excited atoms of xas_tdp_env
1130!> \param xas_tdp_env ...
1131!> \param qs_env ...
1132!> \note The ri_3c_coul tensor of xas_tdp_env is defined and allocated here. Only computed once
1133!> for the whole system (for optimized load balance). Ok because not too much memory needed
1134! **************************************************************************************************
1135 SUBROUTINE compute_ri_3c_coulomb(xas_tdp_env, qs_env)
1136
1137 TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1138 TYPE(qs_environment_type), POINTER :: qs_env
1139
1140 CHARACTER(len=*), PARAMETER :: routinen = 'compute_ri_3c_coulomb'
1141
1142 INTEGER :: handle, natom, nkind
1143 INTEGER, ALLOCATABLE, DIMENSION(:) :: blk_size_orb, blk_size_ri
1144 TYPE(coulomb_operator_type) :: pot
1145 TYPE(dbcsr_distribution_type) :: opt_dbcsr_dist
1146 TYPE(gto_basis_set_p_type), DIMENSION(:), POINTER :: basis_set_orb, basis_set_ri
1147 TYPE(mp_para_env_type), POINTER :: para_env
1148 TYPE(neighbor_list_set_p_type), DIMENSION(:), &
1149 POINTER :: ab_list, ac_list
1150 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set
1151 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1152
1153 NULLIFY (basis_set_ri, basis_set_orb, ac_list, ab_list, qs_kind_set, para_env, particle_set)
1154
1155 CALL timeset(routinen, handle)
1156
1157! Take what we need from the qs_env
1158 CALL get_qs_env(qs_env, nkind=nkind, qs_kind_set=qs_kind_set, para_env=para_env, &
1159 natom=natom, particle_set=particle_set)
1160
1161! Build the basis set lists
1162 ALLOCATE (basis_set_ri(nkind))
1163 ALLOCATE (basis_set_orb(nkind))
1164 CALL basis_set_list_setup(basis_set_ri, "RI_XAS", qs_kind_set)
1165 CALL basis_set_list_setup(basis_set_orb, "ORB", qs_kind_set)
1166
1167! Get the optimized distribution 2d for these integrals (and store it in xas_tdp_env)
1168 CALL build_xas_tdp_ovlp_nl(ab_list, basis_set_orb, basis_set_orb, qs_env, &
1169 excited_atoms=xas_tdp_env%ex_atom_indices)
1170 CALL build_xas_tdp_3c_nl(ac_list, basis_set_orb, basis_set_ri, do_potential_id, &
1171 qs_env, excited_atoms=xas_tdp_env%ex_atom_indices)
1172 CALL get_opt_3c_dist2d(xas_tdp_env%opt_dist2d_coul, ab_list, ac_list, basis_set_orb, &
1173 basis_set_orb, basis_set_ri, qs_env, only_bc_same_center=.true.)
1174 CALL release_neighbor_list_sets(ab_list)
1175 CALL release_neighbor_list_sets(ac_list)
1176
1177! Build a neighbor list for the ab centers. Assume (aI|c) = sum_b c_bI (ab|c), with c_bI only
1178! non-zero for b centered on the same atom as c => build overlap nl, but only keeping b if centered
1179! on an excited atom
1180 CALL build_xas_tdp_ovlp_nl(ab_list, basis_set_orb, basis_set_orb, qs_env, &
1181 excited_atoms=xas_tdp_env%ex_atom_indices, &
1182 ext_dist2d=xas_tdp_env%opt_dist2d_coul)
1183
1184! Build a neighbor list for the ac centers. Since we later contract as (aI|c) and we assume I is
1185! very localized on the same atom as c, we take a,c as neighbors if they overlap
1186 CALL build_xas_tdp_3c_nl(ac_list, basis_set_orb, basis_set_ri, do_potential_id, &
1187 qs_env, excited_atoms=xas_tdp_env%ex_atom_indices, &
1188 ext_dist2d=xas_tdp_env%opt_dist2d_coul)
1189
1190! Allocate, init and compute the integrals
1191 ALLOCATE (blk_size_orb(natom), blk_size_ri(natom))
1192 CALL cp_dbcsr_dist2d_to_dist(xas_tdp_env%opt_dist2d_coul, opt_dbcsr_dist)
1193 CALL get_particle_set(particle_set, qs_kind_set, nsgf=blk_size_orb, basis=basis_set_orb)
1194 CALL get_particle_set(particle_set, qs_kind_set, nsgf=blk_size_ri, basis=basis_set_ri)
1195 pot%potential_type = do_potential_coulomb
1196
1197 ALLOCATE (xas_tdp_env%ri_3c_coul)
1198 CALL create_pqx_tensor(xas_tdp_env%ri_3c_coul, ab_list, ac_list, opt_dbcsr_dist, blk_size_orb, &
1199 blk_size_orb, blk_size_ri, only_bc_same_center=.true.)
1200 CALL fill_pqx_tensor(xas_tdp_env%ri_3c_coul, ab_list, ac_list, basis_set_orb, basis_set_orb, &
1201 basis_set_ri, pot, qs_env, only_bc_same_center=.true.)
1202
1203! Clean-up
1204 CALL release_neighbor_list_sets(ab_list)
1205 CALL release_neighbor_list_sets(ac_list)
1206 CALL dbcsr_distribution_release(opt_dbcsr_dist)
1207 DEALLOCATE (basis_set_ri, basis_set_orb)
1208
1209 !not strictly necessary but avoid having any load unbalance here being reported in the
1210 !timings for other routines
1211 CALL para_env%sync()
1212
1213 CALL timestop(handle)
1214
1215 END SUBROUTINE compute_ri_3c_coulomb
1216
1217! **************************************************************************************************
1218!> \brief Computes the two-center Exchange integral needed for the RI in kernel calculation. Stores
1219!> the integrals in the xas_tdp_env as global (small) arrays. Does that for a given excited
1220!> kind. The quantity stored is M^-1 (P|Q) M^-1, where M is the RI metric. If the metric is
1221!> the same as the exchange potential, then we end up with the V-approximation (P|Q)^-1
1222!> By default (if no metric), the ri_m_potential is a copy of the x_potential
1223!> \param ex_kind ...
1224!> \param xas_tdp_env ...
1225!> \param xas_tdp_control ...
1226!> \param qs_env ...
1227!> \note Computes all these integrals in non-PBCs as we assume that the range is short enough that
1228!> atoms do not exchange with their periodic images
1229! **************************************************************************************************
1230 SUBROUTINE compute_ri_exchange2_int(ex_kind, xas_tdp_env, xas_tdp_control, qs_env)
1231
1232 INTEGER, INTENT(IN) :: ex_kind
1233 TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1234 TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1235 TYPE(qs_environment_type), POINTER :: qs_env
1236
1237 INTEGER :: egfp, egfq, maxl, ncop, ncoq, nset, &
1238 nsgf, pset, qset, sgfp, sgfq
1239 INTEGER, DIMENSION(:), POINTER :: lmax, lmin, npgf_set, nsgf_set
1240 INTEGER, DIMENSION(:, :), POINTER :: first_sgf
1241 REAL(dp) :: r(3)
1242 REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: metric, pq, work
1243 REAL(dp), DIMENSION(:, :), POINTER :: rpgf, sphi, zet
1244 TYPE(coulomb_integral_context_type) :: integral_context
1245 TYPE(gto_basis_set_type), POINTER :: ri_basis
1246 TYPE(mp_para_env_type), POINTER :: para_env
1247 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1248
1249 NULLIFY (ri_basis, qs_kind_set, para_env, lmin, lmax, npgf_set, zet, rpgf, first_sgf)
1250 NULLIFY (sphi, nsgf_set)
1251
1252! Initialization
1253 CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set, para_env=para_env)
1254 IF (ASSOCIATED(xas_tdp_env%ri_inv_ex)) THEN
1255 DEALLOCATE (xas_tdp_env%ri_inv_ex)
1256 END IF
1257
1258! Get the RI basis of interest and its quantum numbers
1259 CALL get_qs_kind(qs_kind_set(ex_kind), basis_set=ri_basis, basis_type="RI_XAS")
1260 CALL get_gto_basis_set(ri_basis, nsgf=nsgf, maxl=maxl, npgf=npgf_set, lmin=lmin, &
1261 lmax=lmax, zet=zet, pgf_radius=rpgf, first_sgf=first_sgf, &
1262 nsgf_set=nsgf_set, sphi=sphi, nset=nset)
1263 ALLOCATE (metric(nsgf, nsgf))
1264 metric = 0.0_dp
1265
1266 r = 0.0_dp
1267
1268 !init the libint 2-center object
1269 CALL coulomb_integral_init(integral_context, max_am_2c=maxl, &
1270 derivative_order=0, library=library_libint)
1271
1272 CALL r12_fundamentals_init(2*maxl + 1, xas_tdp_control%ri_m_potential, para_env)
1273
1274! Compute the RI metric
1275 DO pset = 1, nset
1276 ncop = npgf_set(pset)*ncoset(lmax(pset))
1277 sgfp = first_sgf(1, pset)
1278 egfp = sgfp + nsgf_set(pset) - 1
1279
1280 DO qset = 1, nset
1281 ncoq = npgf_set(qset)*ncoset(lmax(qset))
1282 sgfq = first_sgf(1, qset)
1283 egfq = sgfq + nsgf_set(qset) - 1
1284
1285 ALLOCATE (work(ncop, ncoq))
1286 work = 0.0_dp
1287
1288 CALL compute_coulomb_2c(integral_context, lmin(pset), lmax(pset), lmin(qset), lmax(qset), &
1289 npgf_set(pset), npgf_set(qset), zet(:, pset), zet(:, qset), rpgf(:, pset), rpgf(:, qset), r, r, &
1290 work, xas_tdp_control%ri_m_potential, dab=0.0_dp)
1291
1292 CALL ab_contract(metric(sgfp:egfp, sgfq:egfq), work, sphi(:, sgfp:), sphi(:, sgfq:), &
1293 ncop, ncoq, nsgf_set(pset), nsgf_set(qset))
1294
1295 DEALLOCATE (work)
1296 END DO !qset
1297 END DO !pset
1298
1299! Inverting (to M^-1)
1300 CALL invmat_symm(metric)
1301
1302 IF (.NOT. xas_tdp_control%do_ri_metric) THEN
1303
1304 !If no metric, then x_pot = ri_m_pot and (P|Q)^-1 = M^-1 (V-approximation)
1305 ALLOCATE (xas_tdp_env%ri_inv_ex(nsgf, nsgf))
1306 xas_tdp_env%ri_inv_ex(:, :) = metric(:, :)
1307 CALL coulomb_integral_cleanup(integral_context)
1308 RETURN
1309
1310 END IF
1311
1312 CALL r12_fundamentals_init(2*maxl + 1, xas_tdp_control%x_potential, para_env)
1313
1314! Compute the proper exchange 2-center
1315 ALLOCATE (pq(nsgf, nsgf))
1316 pq = 0.0_dp
1317
1318 DO pset = 1, nset
1319 ncop = npgf_set(pset)*ncoset(lmax(pset))
1320 sgfp = first_sgf(1, pset)
1321 egfp = sgfp + nsgf_set(pset) - 1
1322
1323 DO qset = 1, nset
1324 ncoq = npgf_set(qset)*ncoset(lmax(qset))
1325 sgfq = first_sgf(1, qset)
1326 egfq = sgfq + nsgf_set(qset) - 1
1327
1328 ALLOCATE (work(ncop, ncoq))
1329 work = 0.0_dp
1330
1331 CALL compute_coulomb_2c(integral_context, lmin(pset), lmax(pset), lmin(qset), lmax(qset), &
1332 npgf_set(pset), npgf_set(qset), zet(:, pset), zet(:, qset), rpgf(:, pset), rpgf(:, qset), r, r, &
1333 work, xas_tdp_control%x_potential, dab=0.0_dp)
1334
1335 CALL ab_contract(pq(sgfp:egfp, sgfq:egfq), work, sphi(:, sgfp:), sphi(:, sgfq:), &
1336 ncop, ncoq, nsgf_set(pset), nsgf_set(qset))
1337
1338 DEALLOCATE (work)
1339 END DO !qset
1340 END DO !pset
1341
1342! Compute and store M^-1 (P|Q) M^-1
1343 ALLOCATE (xas_tdp_env%ri_inv_ex(nsgf, nsgf))
1344 xas_tdp_env%ri_inv_ex = 0.0_dp
1345
1346 CALL dgemm('N', 'N', nsgf, nsgf, nsgf, 1.0_dp, metric, nsgf, pq, nsgf, &
1347 0.0_dp, xas_tdp_env%ri_inv_ex, nsgf)
1348 CALL dgemm('N', 'N', nsgf, nsgf, nsgf, 1.0_dp, xas_tdp_env%ri_inv_ex, nsgf, metric, nsgf, &
1349 0.0_dp, pq, nsgf)
1350 xas_tdp_env%ri_inv_ex(:, :) = pq(:, :)
1351
1352 CALL coulomb_integral_cleanup(integral_context)
1353
1354 END SUBROUTINE compute_ri_exchange2_int
1355
1356! **************************************************************************************************
1357!> \brief Computes the two-center Coulomb integral needed for the RI in kernel calculation. Stores
1358!> the integrals (P|Q)^-1 in the xas_tdp_env as global (small) arrays. Does that for a given
1359!> excited kind
1360!> \param ex_kind ...
1361!> \param xas_tdp_env ...
1362!> \param xas_tdp_control ...
1363!> \param qs_env ...
1364! **************************************************************************************************
1365 SUBROUTINE compute_ri_coulomb2_int(ex_kind, xas_tdp_env, xas_tdp_control, qs_env)
1366
1367 INTEGER, INTENT(IN) :: ex_kind
1368 TYPE(xas_tdp_env_type), POINTER :: xas_tdp_env
1369 TYPE(xas_tdp_control_type), POINTER :: xas_tdp_control
1370 TYPE(qs_environment_type), POINTER :: qs_env
1371
1372 INTEGER :: nsgf
1373 TYPE(gto_basis_set_type), POINTER :: ri_basis
1374 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1375
1376 NULLIFY (ri_basis, qs_kind_set)
1377
1378! Initialization
1379 CALL get_qs_env(qs_env, qs_kind_set=qs_kind_set)
1380 IF (ASSOCIATED(xas_tdp_env%ri_inv_coul)) THEN
1381 DEALLOCATE (xas_tdp_env%ri_inv_coul)
1382 END IF
1383
1384! Get the RI basis of interest and its quantum numbers
1385 CALL get_qs_kind(qs_kind_set(ex_kind), basis_set=ri_basis, basis_type="RI_XAS")
1386 CALL get_gto_basis_set(ri_basis, nsgf=nsgf)
1387 ALLOCATE (xas_tdp_env%ri_inv_coul(nsgf, nsgf))
1388 xas_tdp_env%ri_inv_coul = 0.0_dp
1389
1390 IF (.NOT. xas_tdp_control%is_periodic) THEN
1391 CALL int_operators_r12_ab_os(r12_operator=operator_coulomb, vab=xas_tdp_env%ri_inv_coul, &
1392 rab=[0.0_dp, 0.0_dp, 0.0_dp], fba=ri_basis, fbb=ri_basis, &
1393 calculate_forces=.false.)
1394 cpassert(ASSOCIATED(xas_tdp_control))
1395 ELSE
1396 CALL periodic_ri_coulomb2(xas_tdp_env%ri_inv_coul, ri_basis, qs_env)
1397 END IF
1398
1399! Inverting
1400 CALL invmat_symm(xas_tdp_env%ri_inv_coul)
1401
1402 END SUBROUTINE compute_ri_coulomb2_int
1403
1404! **************************************************************************************************
1405!> \brief Computes the two-center inverse coulomb integral in the case of PBCs
1406!> \param ri_coul2 ...
1407!> \param ri_basis ...
1408!> \param qs_env ...
1409! **************************************************************************************************
1410 SUBROUTINE periodic_ri_coulomb2(ri_coul2, ri_basis, qs_env)
1411
1412 REAL(dp), DIMENSION(:, :), INTENT(INOUT) :: ri_coul2
1413 TYPE(gto_basis_set_type), POINTER :: ri_basis
1414 TYPE(qs_environment_type), POINTER :: qs_env
1415
1416 INTEGER :: maxco, ncop, ncoq, nset, op, oq, ppgf, &
1417 pset, qpgf, qset, sgfp, sgfq
1418 INTEGER, DIMENSION(:), POINTER :: lmax, lmin, npgf, nsgf
1419 INTEGER, DIMENSION(:, :), POINTER :: first_sgf
1420 REAL(dp) :: r(3)
1421 REAL(dp), ALLOCATABLE, DIMENSION(:, :) :: hpq
1422 REAL(dp), DIMENSION(:, :), POINTER :: sphi, zet
1423 TYPE(cell_type), POINTER :: cell
1424 TYPE(cp_eri_mme_param) :: mme_param
1425 TYPE(mp_para_env_type), POINTER :: para_env
1426 TYPE(qs_kind_type), DIMENSION(:), POINTER :: qs_kind_set
1427
1428 NULLIFY (cell, qs_kind_set, lmin, lmax, nsgf, npgf, zet, sphi, first_sgf)
1429
1430 ! Use eri_mme for this. Don't want to annoy the user with a full input section just for this
1431 ! tiny bit => initialize our own eri_mme section with the defaults
1432
1433 CALL get_qs_env(qs_env, cell=cell, qs_kind_set=qs_kind_set, para_env=para_env)
1434
1435 CALL eri_mme_init(mme_param%par, n_minimax=20, cutoff=300.0_dp, do_calib_cutoff=.true., &
1436 cutoff_min=10.0_dp, cutoff_max=10000.0_dp, cutoff_eps=0.01_dp, &
1437 cutoff_delta=0.9_dp, sum_precision=1.0e-12_dp, debug=.false., &
1438 debug_delta=1.0e-6_dp, debug_nsum=1000000, unit_nr=0, print_calib=.false., &
1439 do_error_est=.false.)
1440 mme_param%do_calib = .true.
1441
1442 CALL cp_eri_mme_set_params(mme_param, cell, qs_kind_set, basis_type_1="RI_XAS", para_env=para_env)
1443
1444 CALL get_gto_basis_set(ri_basis, lmax=lmax, npgf=npgf, zet=zet, lmin=lmin, nset=nset, &
1445 nsgf_set=nsgf, sphi=sphi, first_sgf=first_sgf, maxco=maxco)
1446
1447 r = 0.0_dp
1448 ALLOCATE (hpq(nset*maxco, nset*maxco))
1449 hpq = 0.0_dp
1450
1451 DO pset = 1, nset
1452 ncop = npgf(pset)*ncoset(lmax(pset))
1453 sgfp = first_sgf(1, pset)
1454
1455 DO qset = 1, nset
1456 ncoq = npgf(qset)*ncoset(lmax(qset))
1457 sgfq = first_sgf(1, qset)
1458
1459 DO ppgf = 1, npgf(pset)
1460 op = (pset - 1)*maxco + (ppgf - 1)*ncoset(lmax(pset))
1461 DO qpgf = 1, npgf(qset)
1462 oq = (qset - 1)*maxco + (qpgf - 1)*ncoset(lmax(qset))
1463
1464 CALL eri_mme_2c_integrate(mme_param%par, lmin(pset), lmax(pset), lmin(qset), &
1465 lmax(qset), zet(ppgf, pset), zet(qpgf, qset), r, hpq, &
1466 op, oq)
1467
1468 END DO !qpgf
1469 END DO ! ppgf
1470
1471 !contraction into sgfs
1472 op = (pset - 1)*maxco + 1
1473 oq = (qset - 1)*maxco + 1
1474
1475 CALL ab_contract(ri_coul2(sgfp:sgfp + nsgf(pset) - 1, sgfq:sgfq + nsgf(qset) - 1), &
1476 hpq(op:op + ncop - 1, oq:oq + ncoq - 1), sphi(:, sgfp:), sphi(:, sgfq:), &
1477 ncop, ncoq, nsgf(pset), nsgf(qset))
1478
1479 END DO !qset
1480 END DO !pset
1481
1482 !celan-up
1483 CALL eri_mme_release(mme_param%par)
1484
1485 END SUBROUTINE periodic_ri_coulomb2
1486
1487END MODULE xas_tdp_integrals
static int imax(int x, int y)
Returns the larger of two given integers (missing from the C standard).
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.
#define idx2(a, i, j)
#define idx3(a, i, j, k)
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...
subroutine, public ab_contract(abint, sab, sphi_a, sphi_b, ncoa, ncob, nsgfa, nsgfb)
contract overlap integrals (a,b) and transfer to spherical Gaussians
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
constants for the different operators of the 2c-integrals
integer, parameter, public operator_coulomb
Common interface for two- and three-center Coulomb integrals.
various utilities that regard array of different kinds: output, allocation,... maybe it is not a good...
methods related to the blacs parallel environment
subroutine, public dbcsr_distribution_release(dist)
...
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)
...
DBCSR operations in CP2K.
subroutine, public cp_dbcsr_dist2d_to_dist(dist2d, dist)
Creates a DBCSR distribution from a distribution_2d.
Interface to Minimax-Ewald method for periodic ERI's to be used in CP2K.
Utility routines to open and close files.
Definition cp_files.F:22
subroutine, public open_file(file_name, unit_number, file_status, file_form, file_action, file_position, file_pad, file_access, debug)
Opens a file and returns its logical unit number.
Definition cp_files.F:197
subroutine, public close_file(unit_number, file_status)
Closes an open file given by its logical unit number.
Definition cp_files.F:64
This is the start of a dbt_api, all publically needed functions are exported here....
Definition dbt_api.F:17
stores a lists of integer that are local to a processor. The idea is that these integers represent ob...
stores a mapping of 2D info (e.g. matrix) on a 2D processor distribution (i.e. blacs grid) where cpus...
subroutine, public distribution_2d_create(distribution_2d, blacs_env, local_rows_ptr, n_local_rows, local_cols_ptr, row_distribution_ptr, col_distribution_ptr, n_local_cols, n_row_distribution, n_col_distribution)
initializes the distribution_2d
Minimax-Ewald (MME) method for calculating 2-center and 3-center electron repulsion integrals (ERI) o...
subroutine, public eri_mme_2c_integrate(param, la_min, la_max, lb_min, lb_max, zeta, zetb, rab, hab, o1, o2, g_count, r_count, normalize, potential, pot_par)
Low-level integration routine for 2-center ERIs.
Types and initialization / release routines for Minimax-Ewald method for electron repulsion integrals...
subroutine, public eri_mme_release(param)
...
subroutine, public eri_mme_init(param, n_minimax, cutoff, do_calib_cutoff, do_error_est, cutoff_min, cutoff_max, cutoff_eps, cutoff_delta, sum_precision, debug, debug_delta, debug_nsum, unit_nr, print_calib)
...
Calculation of contracted, spherical Gaussian integrals using the (OS) integral scheme....
subroutine, public int_operators_r12_ab_os(r12_operator, vab, dvab, rab, fba, fbb, omega, r_cutoff, calculate_forces)
Calcululates the two-center integrals of the type (a|O(r12)|b) using the OS scheme.
collects all constants needed in input so that they can be used without circular dependencies
integer, parameter, public do_potential_truncated
integer, parameter, public do_potential_id
integer, parameter, public do_potential_coulomb
integer, parameter, public do_potential_short
objects that represent the structure of input sections and the data contained in an input section
subroutine, public section_vals_val_get(section_vals, keyword_name, i_rep_section, i_rep_val, n_rep_val, val, l_val, i_val, r_val, c_val, l_vals, i_vals, r_vals, c_vals, explicit)
returns the requested value
Library choices for electronic integral APIs.
real(dp), parameter, public cutoff_screen_factor
integer, parameter, public library_libint
Defines the basic variable types.
Definition kinds.F:23
integer, parameter, public dp
Definition kinds.F:34
Collection of simple mathematical functions and subroutines.
Definition mathlib.F:15
subroutine, public invmat_symm(a, potrf, uplo)
returns inverse of real symmetric, positive definite matrix
Definition mathlib.F:590
Interface to the message passing library MPI.
Define the data structure for the molecule information.
Provides Cartesian and spherical orbital pointers and indices.
integer, dimension(:), allocatable, public ncoset
Define methods related to particle_type.
subroutine, public get_particle_set(particle_set, qs_kind_set, first_sgf, last_sgf, nsgf, nmao, basis, ncgf)
Get the components of a particle set.
Define the data structure for the particle information.
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.
Some utility functions for the calculation of integrals.
subroutine, public basis_set_list_setup(basis_set_list, basis_type, qs_kind_set)
Set up an easy accessible list of the basis sets for all kinds.
Define the quickstep kind type and their sub types.
subroutine, public get_qs_kind(qs_kind, basis_set, basis_type, ncgf, nsgf, all_potential, tnadd_potential, gth_potential, sgp_potential, upf_potential, cneo_potential, se_parameter, dftb_parameter, xtb_parameter, dftb3_param, zatom, zeff, elec_conf, mao, lmax_dftb, alpha_core_charge, ccore_charge, core_charge, core_charge_radius, paw_proj_set, paw_atom, hard_radius, hard0_radius, max_rad_local, covalent_radius, vdw_radius, gpw_type_forced, harmonics, max_iso_not0, max_s_harm, grid_atom, ngrid_ang, ngrid_rad, lmax_rho0, dft_plus_u_atom, l_of_dft_plus_u, n_of_dft_plus_u, u_minus_j, hund_j, u_of_dft_plus_u, j_of_dft_plus_u, alpha_of_dft_plus_u, beta_of_dft_plus_u, j0_of_dft_plus_u, occupation_of_dft_plus_u, dispersion, bs_occupation, magnetization, no_optimize, addel, laddel, naddel, orbitals, max_scf, eps_scf, smear, u_ramping, u_minus_j_target, eps_u_ramping, proj_shell_charge, lr_atom, do_mtlr, u_j_loop, ao_coef, init_u_ramping_each_scf, reltmat, ghost, monovalent, floating, name, element_symbol, pao_basis_size, pao_model_file, pao_potentials, pao_descriptors, nelec)
Get attributes of an atomic kind.
Define the neighbor list data types and the corresponding functionality.
subroutine, public release_neighbor_list_sets(nlists)
releases an array of neighbor_list_sets
subroutine, public neighbor_list_iterator_create(iterator_set, nl, search, nthread)
Neighbor list iterator functions.
subroutine, public nl_set_sub_iterator(iterator_set, ikind, jkind, iatom, mepos)
...
subroutine, public neighbor_list_iterator_release(iterator_set)
...
subroutine, public get_neighbor_list_set_p(neighbor_list_sets, nlist, symmetric)
Return the components of the first neighbor list set.
integer function, public neighbor_list_iterate(iterator_set, mepos)
...
subroutine, public get_iterator_info(iterator_set, mepos, ikind, jkind, nkind, ilist, nlist, inode, nnode, iatom, jatom, r, cell)
...
Generate the atomic neighbor lists.
subroutine, public atom2d_cleanup(atom2d)
free the internals of atom2d
subroutine, public pair_radius_setup(present_a, present_b, radius_a, radius_b, pair_radius, prmin)
...
subroutine, public build_neighbor_lists(ab_list, particle_set, atom, cell, pair_radius, subcells, mic, symmetric, molecular, subset_of_mol, current_subset, operator_type, nlname, atomb_to_keep, stable_images)
Build simple pair neighbor lists.
subroutine, public atom2d_build(atom2d, distribution_1d, distribution_2d, atomic_kind_set, molecule_set, molecule_only, particle_set)
Build some distribution structure of atoms, refactored from build_qs_neighbor_lists.
3-center overlap type integrals containers
subroutine, public get_o3c_iterator_info(o3c_iterator, mepos, iatom, jatom, katom, ikind, jkind, kkind, rij, rik, cellj, cellk, integral, tvec, force_i, force_j, force_k)
...
subroutine, public o3c_iterator_create(o3c, o3c_iterator, nthread)
...
subroutine, public release_o3c_container(o3c_container)
...
subroutine, public o3c_iterator_release(o3c_iterator)
...
integer function, public o3c_iterate(o3c_iterator, mepos)
...
subroutine, public init_o3c_container(o3c, nspin, basis_set_list_a, basis_set_list_b, basis_set_list_c, sab_nl, sac_nl, only_bc_same_center)
...
Radial fundamentals for Gaussian two-electron integrals. Entry m+1 stores order m....
subroutine, public r12_fundamentals_init(m_max, potential_parameter, para_env)
Prepare shared radial evaluator tables before entering a threaded evaluation region.
3-center integrals machinery for the XAS_TDP method
subroutine, public build_xas_tdp_3c_nl(ac_list, basis_a, basis_c, op_type, qs_env, excited_atoms, x_range, ext_dist2d)
Builds a neighbor lists set taylored for 3-center integral within XAS TDP, such that only excited ato...
subroutine, public compute_ri_coulomb2_int(ex_kind, xas_tdp_env, xas_tdp_control, qs_env)
Computes the two-center Coulomb integral needed for the RI in kernel calculation. Stores the integral...
subroutine, public build_xas_tdp_ovlp_nl(ab_list, basis_a, basis_b, qs_env, excited_atoms, ext_dist2d)
Builds a neighbor lists set for overlaping 2-center S_ab, where b is restricted on a a given list of ...
subroutine, public fill_pqx_tensor(pq_x, ab_nl, ac_nl, basis_set_list_a, basis_set_list_b, basis_set_list_c, potential_parameter, qs_env, only_bc_same_center, eps_screen)
Fills the given 3 dimensional (pq|X) tensor with integrals.
subroutine, public compute_ri_3c_coulomb(xas_tdp_env, qs_env)
Computes the RI Coulomb 3-center integrals (ab|c), where c is from the RI_XAS basis and centered on t...
subroutine, public compute_ri_exchange2_int(ex_kind, xas_tdp_env, xas_tdp_control, qs_env)
Computes the two-center Exchange integral needed for the RI in kernel calculation....
subroutine, public create_pqx_tensor(pq_x, ab_nl, ac_nl, matrix_dist, blk_size_1, blk_size_2, blk_size_3, only_bc_same_center)
Prepares a tensor to hold 3-center integrals (pq|X), where p,q are distributed according to the given...
subroutine, public get_opt_3c_dist2d(opt_3c_dist2d, ab_list, ac_list, basis_set_a, basis_set_b, basis_set_c, qs_env, only_bc_same_center)
Returns an optimized distribution_2d for the given neighbor lists based on an evaluation of the cost ...
subroutine, public compute_ri_3c_exchange(ex_atoms, xas_tdp_env, xas_tdp_control, qs_env)
Computes the RI exchange 3-center integrals (ab|c), where c is from the RI_XAS basis and centered on ...
Define XAS TDP control type and associated create, release, etc subroutines, as well as XAS TDP envir...
Provides all information about an atomic kind.
Type defining parameters related to the simulation cell.
Definition cell_types.F:60
represent a pointer to a 1d array
represent a pointer to a 2d array
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
structure to store local (to a processor) ordered lists of integers.
distributes pairs on a 2d grid of processors
stores all the informations relevant to an mpi environment
Provides all information about a quickstep kind.
Type containing control information for TDP XAS calculations.
Type containing informations such as inputs and results for TDP XAS calculations.