65#include "./base/base_uses.f90"
70 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'gw_compute_Z_lP'
95 SUBROUTINE compute_z_lp(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_Z_lP)
98 REAL(kind=
dp),
ALLOCATABLE,
INTENT(INOUT) :: ri_rs_grid_points(:, :)
99 TYPE(
dbcsr_type),
INTENT(INOUT) :: mat_phi_mu_l
102 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_Z_lP'
106 CALL timeset(routinen, handle)
108 IF (bs_env%auto_ri%enabled)
THEN
109 CALL compute_z_lp_auto_ri(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_z_lp)
111 CALL compute_z_lp_standard(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_z_lp)
114 CALL timestop(handle)
140 SUBROUTINE compute_z_lp_standard(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_Z_lP)
144 REAL(kind=
dp),
ALLOCATABLE,
INTENT(INOUT) :: ri_rs_grid_points(:, :)
145 TYPE(
dbcsr_type),
INTENT(INOUT) :: mat_phi_mu_l
148 CHARACTER(LEN=*),
PARAMETER :: key =
'PROPERTIES%BANDSTRUCTURE%GW%PRINT%RESTART', &
149 routinen =
'compute_Z_lP_standard'
151 INTEGER :: atom_j_mepos, atom_j_stride, atom_p, g, handle, handle_dpotrf, handle_dpotrs, &
152 i_blk, iatom,
idx, info, iphase, j, max_ao_size, my_group, n_ao_total, n_ao_used, n_big, &
153 n_done, n_groups, n_loc_ri, n_local_grid, n_my_atoms, n_small, natom, npcol_phi, &
154 num_grid_chunks, phase_hi
155 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: ao_col_map, big_list, local_grid_idx, &
156 my_atoms_a, my_atoms_b, &
157 n_local_grid_atom, row_offset, &
159 INTEGER,
DIMENSION(:),
POINTER :: col_dist_ri, r_blk_sizes, ri_blk_sizes, &
161 LOGICAL :: do_scatter, use_dist
162 REAL(kind=
dp) :: balance_a, balance_b, cutoff_ri, &
163 item_start_time, r_c, t1
164 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: cutoff_ri_per_atom, d_vec_local
165 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: d_local, d_lp_local, phi_local
176 TYPE(
qs_kind_type),
DIMENSION(:),
POINTER :: qs_kind_set
179 CALL timeset(routinen, handle)
183 CALL get_qs_env(qs_env, para_env=para_env, particle_set=particle_set, input=input, &
184 qs_kind_set=qs_kind_set, cell=cell, atomic_kind_set=atomic_kind_set)
186 NULLIFY (para_env_sub, blacs_env_sub)
188 natom = bs_env%n_atom
189 n_ao_total = bs_env%i_ao_end_from_atom(natom)
196 CALL dbcsr_get_info(mat_phi_mu_l, row_blk_size=r_blk_sizes, distribution=dist_phi)
199 num_grid_chunks =
SIZE(r_blk_sizes)
201 ALLOCATE (row_offset(num_grid_chunks))
203 DO i_blk = 2, num_grid_chunks
204 row_offset(i_blk) = row_offset(i_blk - 1) + r_blk_sizes(i_blk - 1)
207 ALLOCATE (ri_blk_sizes(natom), col_dist_ri(natom))
209 ri_blk_sizes(iatom) = &
210 bs_env%i_RI_end_from_atom(iatom) - bs_env%i_RI_start_from_atom(iatom) + 1
211 col_dist_ri(iatom) = mod(iatom - 1, npcol_phi)
215 row_dist=row_dist_grid, col_dist=col_dist_ri)
217 IF (bs_env%ri_rs%Z_lP_exists)
THEN
219 distribution=dist_z, &
221 IF (bs_env%unit_nr > 0)
THEN
222 WRITE (bs_env%unit_nr,
'(T2,A,T57,A,F7.1,A)') &
223 'Read Z_lP from file ',
' Execution time',
m_walltime() - t1,
' s'
227 WRITE (bs_env%unit_nr,
'(T2,A)') &
228 '*** NOTE: Z_lP restart must match the current (spatial) grid row ordering ***'
229 WRITE (bs_env%unit_nr,
'(A)')
' '
233 IF (bs_env%unit_nr > 0)
THEN
234 WRITE (bs_env%unit_nr,
'(A)')
' '
235 WRITE (bs_env%unit_nr,
'(T2,A)')
'Started computing Z_lP'
238 CALL dbcsr_create(mat_z_lp, name=
"mat_Z_lP", dist=dist_z, &
239 matrix_type=dbcsr_type_no_symmetry, &
240 row_blk_size=r_blk_sizes, col_blk_size=ri_blk_sizes)
244 DO j = 1, bs_env%n_atom
245 max_ao_size = max(max_ao_size, &
246 bs_env%i_ao_end_from_atom(j) - &
247 bs_env%i_ao_start_from_atom(j) + 1)
255 ALLOCATE (cutoff_ri_per_atom(natom))
257 IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp)
THEN
258 cutoff_ri_per_atom(:) = bs_env%ri_rs%cutoff_radius_ri_rs
260 r_c = bs_env%ri_metric%cutoff_radius
262 cutoff_ri_per_atom(iatom) = r_c + bs_env%ri_rs%radius_ri_per_atom(iatom)
266 CALL print_sphere_cutoff_table(bs_env, cutoff_ri_per_atom)
274 CALL classify_z_lp_atoms(bs_env, ri_rs_grid_points, cutoff_ri_per_atom, ri_blk_sizes, &
275 n_local_grid_atom, small_list, n_small, big_list, n_big, g)
280 CALL lpt_assign_atoms(small_list, n_small, n_local_grid_atom, para_env%num_pe, &
281 para_env%mepos, my_atoms_a, balance_a)
283 n_groups = para_env%num_pe/g
284 my_group = min(para_env%mepos/g, n_groups - 1)
285 CALL lpt_assign_atoms(big_list, n_big, n_local_grid_atom, n_groups, my_group, &
286 my_atoms_b, balance_b)
288 ALLOCATE (my_atoms_b(0))
293 n_my_atoms =
SIZE(my_atoms_a) +
SIZE(my_atoms_b)
298 basis_j=bs_env%basis_set_AO, basis_k=bs_env%basis_set_AO, &
299 basis_i=bs_env%basis_set_RI)
309 IF (iphase == 1)
THEN
313 phase_hi =
SIZE(my_atoms_a)
315 IF (n_big == 0) cycle
317 n_groups = para_env%num_pe/g
318 my_group = min(para_env%mepos/g, n_groups - 1)
319 ALLOCATE (para_env_sub)
320 CALL para_env_sub%from_split(para_env, my_group)
322 atom_j_mepos = para_env_sub%mepos
323 atom_j_stride = para_env_sub%num_pe
326 phase_hi =
SIZE(my_atoms_b)
331 IF (iphase == 1)
THEN
332 atom_p = my_atoms_a(
idx)
334 atom_p = my_atoms_b(
idx)
337 n_loc_ri = ri_blk_sizes(atom_p)
338 cutoff_ri = cutoff_ri_per_atom(atom_p)
345 CALL build_phi_on_sphere(bs_env, qs_kind_set, &
346 ri_rs_grid_points, atom_p, cutoff_ri, n_ao_total, &
347 local_grid_idx, n_local_grid, phi_local, &
348 ao_col_map, n_ao_used)
353 ALLOCATE (d_lp_local(n_local_grid, n_loc_ri))
356 CALL compute_d_lp(bs_env, ctx_3c, phi_local, ao_col_map, d_lp_local, n_local_grid, &
357 n_loc_ri, atom_p, max_ao_size, atom_j_mepos, atom_j_stride)
362 CALL para_env_sub%sum(d_lp_local)
369 ALLOCATE (d_vec_local(n_local_grid))
371 IF (.NOT. use_dist)
THEN
373 bs_env%ri_rs%tikhonov, d_local, d_vec_local)
391 IF (.NOT. use_dist)
THEN
392 CALL timeset(routinen//
"_dpotrf", handle_dpotrf)
393 CALL dpotrf(
'L', n_local_grid, d_local, n_local_grid, info)
394 CALL timestop(handle_dpotrf)
395 IF (info /= 0) cpabort(
"RI-RS Cholesky factorization failed")
396 CALL timeset(routinen//
"_dpotrs", handle_dpotrs)
397 CALL dpotrs(
'L', n_local_grid, n_loc_ri, d_local, n_local_grid, &
398 d_lp_local, n_local_grid, info)
399 CALL timestop(handle_dpotrs)
400 IF (info /= 0) cpabort(
"RI-RS Cholesky solve failed")
404 n_local_grid, n_ao_used, n_loc_ri, &
405 bs_env%ri_rs%tikhonov, &
406 para_env_sub, blacs_env_sub, &
407 fm_struct_d, fm_struct_b, fm_d, fm_b, info)
408 IF (info /= 0) cpabort(
"Distributed RI-RS Cholesky solve failed")
420 IF (use_dist) do_scatter = (para_env_sub%mepos == 0)
423 n_loc_ri, atom_p, r_blk_sizes, row_offset, &
427 DEALLOCATE (d_vec_local, d_lp_local)
428 DEALLOCATE (local_grid_idx, phi_local, ao_col_map)
433 CALL print_z_lp_progress(bs_env, n_done, n_my_atoms, &
438 IF (iphase == 2)
THEN
440 CALL para_env_sub%free()
441 DEALLOCATE (para_env_sub)
445 DEALLOCATE (cutoff_ri_per_atom)
446 DEALLOCATE (small_list, big_list)
453 CALL print_z_lp_progress(bs_env, natom, natom,
m_walltime() - t1, &
454 all_mpi_ranks=.true.)
464 DEALLOCATE (row_offset, ri_blk_sizes, col_dist_ri)
467 DEALLOCATE (ri_rs_grid_points)
469 CALL timestop(handle)
471 END SUBROUTINE compute_z_lp_standard
478 SUBROUTINE print_sphere_cutoff_table(bs_env, cutoff_ri_per_atom)
481 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: cutoff_ri_per_atom
483 CHARACTER(LEN=*),
PARAMETER :: routinen =
'print_sphere_cutoff_table'
485 INTEGER :: handle, iatom, ikind, nkind
486 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: cutoff_ri_per_kind
490 CALL timeset(routinen, handle)
492 atomic_kind_set => bs_env%ri_rs%atomic_kind_set
493 particle_set => bs_env%ri_rs%particle_set
495 IF (bs_env%unit_nr <= 0)
THEN
496 CALL timestop(handle)
500 nkind =
SIZE(atomic_kind_set)
501 ALLOCATE (cutoff_ri_per_kind(nkind))
502 cutoff_ri_per_kind(:) = 0.0_dp
504 DO iatom = 1, bs_env%n_atom
505 ikind = particle_set(iatom)%atomic_kind%kind_number
506 cutoff_ri_per_kind(ikind) = max(cutoff_ri_per_kind(ikind), cutoff_ri_per_atom(iatom))
509 WRITE (bs_env%unit_nr,
'(T2,A)')
'Per-kind maximum RI-RS sphere cutoff (Å):'
510 WRITE (bs_env%unit_nr,
'(T4,A4,A14)')
'Kind',
'cutoff (Å)'
512 WRITE (bs_env%unit_nr,
'(T4,A4,F14.4)') &
513 atomic_kind_set(ikind)%element_symbol, &
516 WRITE (bs_env%unit_nr,
'(A)')
' '
518 DEALLOCATE (cutoff_ri_per_kind)
520 CALL timestop(handle)
522 END SUBROUTINE print_sphere_cutoff_table
537 SUBROUTINE lpt_assign_atoms(atom_list, n_atoms, n_local_grid_atom, n_workers, my_worker, &
538 my_atoms, max_over_mean)
540 INTEGER,
DIMENSION(:),
INTENT(IN) :: atom_list
541 INTEGER,
INTENT(IN) :: n_atoms
542 INTEGER,
DIMENSION(:),
INTENT(IN) :: n_local_grid_atom
543 INTEGER,
INTENT(IN) :: n_workers, my_worker
544 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: my_atoms
545 REAL(kind=
dp),
INTENT(OUT) :: max_over_mean
547 CHARACTER(LEN=*),
PARAMETER :: routinen =
'lpt_assign_atoms'
549 INTEGER :: handle, i, iw, n_mine, w_min
550 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: mine_tmp, perm
551 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: cost, load
553 CALL timeset(routinen, handle)
555 max_over_mean = 1.0_dp
556 IF (n_atoms <= 0)
THEN
557 ALLOCATE (my_atoms(0))
558 CALL timestop(handle)
562 ALLOCATE (cost(n_atoms), perm(n_atoms), mine_tmp(n_atoms), load(n_workers))
564 cost(i) = real(n_local_grid_atom(atom_list(i)),
dp)**3
566 CALL sort(cost, n_atoms, perm)
570 DO i = n_atoms, 1, -1
573 IF (load(iw) < load(w_min)) w_min = iw
575 load(w_min) = load(w_min) + cost(i)
576 IF (w_min - 1 == my_worker)
THEN
578 mine_tmp(n_mine) = atom_list(perm(i))
582 ALLOCATE (my_atoms(n_mine))
583 my_atoms(:) = mine_tmp(1:n_mine)
584 IF (sum(load) > 0.0_dp) max_over_mean = maxval(load)*real(n_workers,
dp)/sum(load)
586 CALL timestop(handle)
588 END SUBROUTINE lpt_assign_atoms
611 SUBROUTINE compute_d_lp(bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid_total, n_loc_ri, atom_P, &
612 max_ao_size, atom_j_mepos, atom_j_stride)
616 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: phi_val
617 INTEGER,
DIMENSION(:),
INTENT(IN) :: ao_col_map
618 INTEGER,
INTENT(IN) :: n_grid_total, n_loc_ri
619 REAL(kind=
dp),
INTENT(INOUT) :: d_lp(n_grid_total, n_loc_ri)
620 INTEGER,
INTENT(IN) :: atom_p, max_ao_size, atom_j_mepos, &
623 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_d_lp'
624 INTEGER,
PARAMETER :: grid_chunk = 1024
626 INTEGER :: atom_j, atom_k, c, handle, handle_dgemm, &
627 j, jk_idx, jsize, jstart, k, ksize, &
628 kstart, l, l0, n_grid_pair, point, ri
629 INTEGER,
ALLOCATABLE :: grid_index(:)
631 LOGICAL,
ALLOCATABLE :: skip_grid_point(:, :)
632 REAL(kind=
dp) :: pair_factor
633 REAL(kind=
dp),
ALLOCATABLE :: grid_result(:, :)
634 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: d_lp_prv, int_2d_prv, rho_chunk
635 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: int_3c_prv
638 CALL timeset(routinen, handle)
648 ALLOCATE (int_3c_prv(max_ao_size, max_ao_size, n_loc_ri))
649 ALLOCATE (int_2d_prv(max_ao_size*max_ao_size, n_loc_ri))
650 ALLOCATE (rho_chunk(grid_chunk, max_ao_size*max_ao_size))
651 ALLOCATE (d_lp_prv(n_grid_total, n_loc_ri))
652 ALLOCATE (grid_index(n_grid_total), grid_result(grid_chunk, n_loc_ri))
653 d_lp_prv(:, :) = 0.0_dp
656 ALLOCATE (skip_grid_point(n_grid_total, bs_env%n_atom))
657 CALL compute_skip_grid_point(bs_env, phi_val, ao_col_map, skip_grid_point)
663 DO atom_j = atom_j_mepos + 1, bs_env%n_atom, atom_j_stride
664 DO atom_k = atom_j, bs_env%n_atom
665 jstart = ao_col_map(bs_env%i_ao_start_from_atom(atom_j))
666 kstart = ao_col_map(bs_env%i_ao_start_from_atom(atom_k))
667 IF (jstart == 0 .OR. kstart == 0) cycle
668 jsize = bs_env%i_ao_end_from_atom(atom_j) - bs_env%i_ao_start_from_atom(atom_j) + 1
669 ksize = bs_env%i_ao_end_from_atom(atom_k) - bs_env%i_ao_start_from_atom(atom_k) + 1
672 DO point = 1, n_grid_total
673 IF (skip_grid_point(point, atom_j) .OR. skip_grid_point(point, atom_k)) cycle
674 n_grid_pair = n_grid_pair + 1
675 grid_index(n_grid_pair) = point
677 IF (n_grid_pair == 0) cycle
680 IF (atom_j /= atom_k) pair_factor = 2.0_dp
682 int_3c_prv(1:jsize, 1:ksize, 1:n_loc_ri) = 0.0_dp
687 ctx, ws, atom_j=atom_j, atom_k=atom_k, atom_i=atom_p, &
696 jk_idx = (k - 1)*jsize + j
697 int_2d_prv(jk_idx, ri) = int_3c_prv(j, k, ri)
704 DO l0 = 1, n_grid_pair, grid_chunk
705 c = min(grid_chunk, n_grid_pair - l0 + 1)
708 jk_idx = (k - 1)*jsize + j
710 point = grid_index(l0 + l - 1)
711 rho_chunk(l, jk_idx) = phi_val(point, jstart + j - 1)* &
712 phi_val(point, kstart + k - 1)
716 CALL timeset(routinen//
"_dgemm", handle_dgemm)
717 CALL dgemm(
"N",
"N", c, n_loc_ri, jsize*ksize, &
718 pair_factor, rho_chunk, grid_chunk, &
719 int_2d_prv, max_ao_size*max_ao_size, &
720 0.0_dp, grid_result, grid_chunk)
723 point = grid_index(l0 + l - 1)
724 d_lp_prv(point, ri) = d_lp_prv(point, ri) + grid_result(l, ri)
727 CALL timestop(handle_dgemm)
734 d_lp(1:n_grid_total, 1:n_loc_ri) = d_lp(1:n_grid_total, 1:n_loc_ri) + &
735 d_lp_prv(1:n_grid_total, 1:n_loc_ri)
738 DEALLOCATE (int_3c_prv, int_2d_prv, rho_chunk, d_lp_prv, grid_index, grid_result)
742 DEALLOCATE (skip_grid_point)
747 CALL timestop(handle)
749 END SUBROUTINE compute_d_lp
758 SUBROUTINE compute_skip_grid_point(bs_env, phi_val, ao_col_map, skip_grid_point)
761 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: phi_val
762 INTEGER,
DIMENSION(:),
INTENT(IN) :: ao_col_map
763 LOGICAL,
DIMENSION(:, :),
INTENT(OUT) :: skip_grid_point
765 INTEGER ::
atom, first_ao, number_of_aos
767 skip_grid_point(:, :) = .true.
768 DO atom = 1, bs_env%n_atom
769 first_ao = ao_col_map(bs_env%i_ao_start_from_atom(
atom))
770 IF (first_ao == 0) cycle
771 number_of_aos = bs_env%i_ao_end_from_atom(
atom) - bs_env%i_ao_start_from_atom(
atom) + 1
772 skip_grid_point(:,
atom) = all(phi_val(:, first_ao:first_ao + number_of_aos - 1) == 0.0_dp, dim=2)
775 END SUBROUTINE compute_skip_grid_point
801 SUBROUTINE compute_z_lp_auto_ri(qs_env, bs_env, ri_rs_grid_points, mat_phi_mu_l, mat_Z_lP)
804 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: ri_rs_grid_points
805 TYPE(
dbcsr_type),
INTENT(INOUT) :: mat_phi_mu_l
808 CHARACTER(LEN=*),
PARAMETER :: key =
'PROPERTIES%BANDSTRUCTURE%GW%PRINT%RESTART', &
809 routinen =
'compute_Z_lP_auto_ri'
811 INTEGER :: ab_block, atom_a, atom_b, block_size_b, column_first, first_p_ab, fit_atom, &
812 handle, handle_dpotrf, handle_dpotrs, info, max_ao_size, max_nri_ref, mypcol, myprow, &
813 n_ao_total, n_ao_used, n_done, n_my_atoms, n_to_a, natom, ncol, ngrid, nri, nri_ref_a, &
814 nri_ref_b, output_offset, ri_atom
815 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: ao_col_map, local_grid_idx, row_offset
816 INTEGER,
DIMENSION(:),
POINTER :: col_dist_ri, ri_blk_sizes, &
817 row_dist_grid, row_size_grid
818 LOGICAL :: ab_block_local, common_grid_available, &
819 have_fitted_columns, &
820 reuse_atomic_integrals
821 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: active_atom
822 REAL(kind=
dp) :: cutoff_ri, item_start_time, r_c, t1
823 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: d_vec
824 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: d_local, d_lp_all, d_lp_local, &
826 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: u_pp_by_atom
827 REAL(kind=
dp),
DIMENSION(3) :: center
835 TYPE(
qs_kind_type),
DIMENSION(:),
POINTER :: qs_kind_set
838 CALL timeset(routinen, handle)
840 IF (bs_env%unit_nr > 0)
THEN
841 WRITE (bs_env%unit_nr,
'(A)')
' '
842 WRITE (bs_env%unit_nr,
'(T2,A)')
'Started computing Z_lP'
845 CALL get_qs_env(qs_env, para_env=para_env, particle_set=particle_set, input=input, &
846 qs_kind_set=qs_kind_set, cell=cell)
847 NULLIFY (para_env_col)
849 natom = bs_env%n_atom
850 n_ao_total = bs_env%i_ao_end_from_atom(natom)
851 cpassert(bs_env%auto_ri%AB_block_count > 0)
852 cpassert(
SIZE(particle_set) == natom)
854 CALL prepare_z_lp_auto_ri(bs_env, mat_phi_mu_l, mat_z_lp, dist_z, row_size_grid, &
855 row_dist_grid, col_dist_ri, ri_blk_sizes, row_offset, &
856 myprow, mypcol, max_ao_size)
859 basis_j=bs_env%basis_set_AO, basis_k=bs_env%basis_set_AO, &
860 basis_i=bs_env%basis_set_RI)
863 CALL common_z_lp_grid_available(bs_env, ri_rs_grid_points, &
864 common_grid_available, have_fitted_columns)
866 IF (common_grid_available .AND. have_fitted_columns)
THEN
868 CALL build_phi_on_complete_grid(bs_env, qs_kind_set, &
869 ri_rs_grid_points, n_ao_total, local_grid_idx, ngrid, &
870 phi_local, ao_col_map, n_ao_used)
871 nri = sum(ri_blk_sizes)
872 ALLOCATE (d_lp_all(ngrid, nri), source=0.0_dp)
874 CALL compute_d_lp_auto_ri_batch(bs_env, ctx_3c, phi_local, ao_col_map, d_lp_all, ngrid, &
875 max_ao_size, para_env%mepos, para_env%num_pe)
876 CALL para_env%sum(d_lp_all)
877 ALLOCATE (d_vec(ngrid))
882 CALL timeset(routinen//
'_dpotrf', handle_dpotrf)
883 CALL dpotrf(
'L', ngrid, d_local, ngrid, info)
884 CALL timestop(handle_dpotrf)
886 CALL timeset(routinen//
'_dpotrs', handle_dpotrs)
887 CALL dpotrs(
'L', ngrid, nri, d_local, ngrid, d_lp_all, ngrid, info)
888 CALL timestop(handle_dpotrs)
892 DO ab_block = 1, bs_env%auto_ri%AB_block_count
893 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
894 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
895 ab_block_local = col_dist_ri(atom_a) == mypcol
896 IF (atom_b /= atom_a) ab_block_local = ab_block_local .OR. col_dist_ri(atom_b) == mypcol
897 IF (.NOT. ab_block_local) cycle
898 ncol = bs_env%auto_ri%AB_size_opt_RI(ab_block)
899 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
900 IF (n_to_a > 0 .AND. col_dist_ri(atom_a) == mypcol)
THEN
901 output_offset = sum(ri_blk_sizes(:atom_a - 1)) + &
902 bs_env%auto_ri%AB_first_p_A(ab_block) - 1
903 CALL add_z_lp_columns(mat_z_lp, &
904 d_lp_all(:, output_offset + 1:output_offset + n_to_a), &
905 local_grid_idx, ngrid, atom_a, &
906 bs_env%auto_ri%AB_first_p_A(ab_block), &
907 ri_blk_sizes(atom_a), row_size_grid, row_offset, &
909 myprow, bs_env%eps_filter)
911 IF (n_to_a < ncol)
THEN
912 cpassert(atom_b /= atom_a)
913 IF (col_dist_ri(atom_b) == mypcol)
THEN
914 block_size_b = ri_blk_sizes(atom_b)
915 output_offset = sum(ri_blk_sizes(:atom_b - 1)) + &
916 bs_env%auto_ri%AB_first_p_B(ab_block) - 1
917 CALL add_z_lp_columns(mat_z_lp, &
918 d_lp_all(:, output_offset + 1: &
919 output_offset + ncol - n_to_a), &
920 local_grid_idx, ngrid, atom_b, &
921 bs_env%auto_ri%AB_first_p_B(ab_block), block_size_b, &
922 row_size_grid, row_offset, row_dist_grid, myprow, &
927 DEALLOCATE (d_local, d_vec, d_lp_all, local_grid_idx, phi_local, ao_col_map)
929 reuse_atomic_integrals = &
930 bs_env%ri_rs%cutoff_radius_ri_ao <= 0.0_dp .OR. &
931 bs_env%ri_rs%cutoff_radius_ri_ao <= &
932 minval(bs_env%ri_rs%radius_ao_per_atom)
933 IF (reuse_atomic_integrals)
THEN
935 CALL compute_auto_ri_d_lp(qs_env, bs_env, ctx_3c, &
936 ri_rs_grid_points, mat_phi_mu_l, mat_rhs, &
939 CALL dbcsr_create(mat_z_lp, name=
'mat_Z_lP localized AA/AB', dist=dist_z, &
940 matrix_type=dbcsr_type_no_symmetry, row_blk_size=row_size_grid, &
941 col_blk_size=ri_blk_sizes)
943 CALL fit_auto_ri_z_lp(qs_env, bs_env, ri_rs_grid_points, mat_rhs, mat_z_lp)
946 ALLOCATE (para_env_col)
947 CALL para_env_col%from_split(para_env, mypcol)
949 DO fit_atom = 1, natom
950 IF (col_dist_ri(fit_atom) /= mypcol) cycle
951 IF (ri_blk_sizes(fit_atom) == 0) cycle
952 n_my_atoms = n_my_atoms + 1
956 DO ri_atom = 1, natom
957 max_nri_ref = max(max_nri_ref, get_ref_ri_size(bs_env, ri_atom))
959 DO fit_atom = 1, natom
960 IF (col_dist_ri(fit_atom) /= mypcol) cycle
961 ncol = ri_blk_sizes(fit_atom)
964 ALLOCATE (u_pp_by_atom(max_nri_ref, ncol, natom), source=0.0_dp)
965 ALLOCATE (active_atom(natom), source=.false.)
967 DO ab_block = 1, bs_env%auto_ri%AB_block_count
968 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
969 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
970 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
971 IF (fit_atom == atom_a .AND. n_to_a > 0)
THEN
972 column_first = bs_env%auto_ri%AB_first_p_A(ab_block)
975 ELSE IF (fit_atom == atom_b .AND. &
976 n_to_a < bs_env%auto_ri%AB_size_opt_RI(ab_block))
THEN
977 column_first = bs_env%auto_ri%AB_first_p_B(ab_block)
978 first_p_ab = n_to_a + 1
979 ncol = bs_env%auto_ri%AB_size_opt_RI(ab_block) - n_to_a
983 CALL get_u_pp_ab(bs_env%auto_ri, ab_block, u_pp_ab)
985 nri_ref_a = get_ref_ri_size(bs_env, atom_a)
986 u_pp_by_atom(1:nri_ref_a, &
987 column_first:column_first + ncol - 1, atom_a) = &
989 1:nri_ref_a, first_p_ab:first_p_ab + ncol - 1)
990 active_atom(atom_a) = .true.
991 IF (atom_b /= atom_a)
THEN
992 nri_ref_b = get_ref_ri_size(bs_env, atom_b)
993 u_pp_by_atom(1:nri_ref_b, &
994 column_first:column_first + ncol - 1, atom_b) = &
996 nri_ref_a + 1:nri_ref_a + nri_ref_b, &
997 first_p_ab:first_p_ab + ncol - 1)
998 active_atom(atom_b) = .true.
1000 DEALLOCATE (u_pp_ab)
1003 center = particle_set(fit_atom)%r
1004 IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp)
THEN
1005 cutoff_ri = bs_env%ri_rs%cutoff_radius_ri_rs
1007 r_c = bs_env%ri_metric%cutoff_radius
1009 DO ri_atom = 1, natom
1010 IF (.NOT. active_atom(ri_atom)) cycle
1011 cutoff_ri = max(cutoff_ri, &
1012 r_c + bs_env%ri_rs%radius_ri_per_atom(ri_atom) + &
1013 norm2(center - particle_set(ri_atom)%r))
1016 CALL build_phi_on_sphere(bs_env, qs_kind_set, &
1017 ri_rs_grid_points, fit_atom, cutoff_ri, n_ao_total, &
1018 local_grid_idx, ngrid, phi_local, ao_col_map, n_ao_used, &
1020 ncol = ri_blk_sizes(fit_atom)
1021 ALLOCATE (d_lp_local(ngrid, ncol), source=0.0_dp)
1023 CALL compute_d_lp_auto_ri_atoms(bs_env, ctx_3c, phi_local, ao_col_map, &
1024 d_lp_local, ngrid, u_pp_by_atom, &
1025 active_atom, max_ao_size, &
1026 para_env_col%mepos, para_env_col%num_pe)
1027 CALL para_env_col%sum(d_lp_local)
1028 ALLOCATE (d_vec(ngrid))
1033 CALL timeset(routinen//
'_dpotrf', handle_dpotrf)
1034 CALL dpotrf(
'L', ngrid, d_local, ngrid, info)
1035 CALL timestop(handle_dpotrf)
1037 CALL timeset(routinen//
'_dpotrs', handle_dpotrs)
1038 CALL dpotrs(
'L', ngrid, ncol, d_local, ngrid, d_lp_local, ngrid, info)
1039 CALL timestop(handle_dpotrs)
1042 CALL add_z_lp_columns(mat_z_lp, d_lp_local, local_grid_idx, ngrid, fit_atom, 1, &
1043 ri_blk_sizes(fit_atom), row_size_grid, row_offset, &
1045 myprow, bs_env%eps_filter)
1046 DEALLOCATE (d_local, d_vec, d_lp_local, local_grid_idx, phi_local, ao_col_map)
1047 DEALLOCATE (u_pp_by_atom, active_atom)
1049 CALL print_z_lp_progress(bs_env, n_done, n_my_atoms, &
1052 CALL para_env_col%free()
1053 DEALLOCATE (para_env_col)
1060 CALL para_env%sync()
1061 CALL print_z_lp_progress(bs_env, natom, natom,
m_walltime() - t1, &
1062 all_mpi_ranks=.true.)
1065 CALL dbcsr_binary_write(matrix=mat_z_lp, filepath=trim(bs_env%prefix)//
'Z_lP.matrix')
1068 DEALLOCATE (row_offset, ri_blk_sizes, col_dist_ri)
1070 CALL timestop(handle)
1072 END SUBROUTINE compute_z_lp_auto_ri
1082 SUBROUTINE print_z_lp_progress(bs_env, n_done, n_total, execution_time, all_mpi_ranks)
1084 INTEGER,
INTENT(IN) :: n_done, n_total
1085 REAL(kind=
dp),
INTENT(IN) :: execution_time
1086 LOGICAL,
INTENT(IN),
OPTIONAL :: all_mpi_ranks
1088 CHARACTER(LEN=*),
PARAMETER :: routinen =
'print_Z_lP_progress'
1091 LOGICAL :: completed
1093 CALL timeset(routinen, handle)
1095 IF (bs_env%unit_nr > 0)
THEN
1097 IF (
PRESENT(all_mpi_ranks)) completed = all_mpi_ranks
1099 WRITE (bs_env%unit_nr,
'(T2,A,T58,A,F7.1,A,/)') &
1100 'Computed Z_lP (all MPI ranks) for all atoms,', &
1101 'Execution time', execution_time,
' s'
1103 WRITE (bs_env%unit_nr,
'(T2,A,I11,A,I3,A,F7.1,A)') &
1104 'Computed Z_lP (MPI rank 0) for atom', n_done,
' /', n_total, &
1105 ', Execution time', execution_time,
' s'
1110 CALL timestop(handle)
1112 END SUBROUTINE print_z_lp_progress
1131 SUBROUTINE prepare_z_lp_auto_ri(bs_env, mat_phi_mu_l, mat_Z_lP, dist_Z, row_size_grid, &
1132 row_dist_grid, col_dist_ri, ri_blk_sizes, row_offset, &
1133 myprow, mypcol, max_ao_size)
1138 INTEGER,
DIMENSION(:),
POINTER :: row_size_grid, row_dist_grid, &
1139 col_dist_ri, ri_blk_sizes
1140 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: row_offset
1141 INTEGER,
INTENT(OUT) :: myprow, mypcol, max_ao_size
1143 CHARACTER(LEN=*),
PARAMETER :: routinen =
'prepare_Z_lP_auto_ri'
1145 INTEGER :: handle, i_blk, iatom, npcol
1148 CALL timeset(routinen, handle)
1150 CALL dbcsr_get_info(mat_phi_mu_l, row_blk_size=row_size_grid, distribution=dist_phi)
1152 myprow=myprow, mypcol=mypcol)
1153 ALLOCATE (row_offset(
SIZE(row_size_grid)))
1155 DO i_blk = 2,
SIZE(row_size_grid)
1156 row_offset(i_blk) = row_offset(i_blk - 1) + row_size_grid(i_blk - 1)
1159 ALLOCATE (ri_blk_sizes(bs_env%n_atom), col_dist_ri(bs_env%n_atom))
1160 ri_blk_sizes = bs_env%auto_ri%sizes_opt_RI
1161 DO iatom = 1, bs_env%n_atom
1162 col_dist_ri(iatom) = mod(iatom - 1, npcol)
1165 col_dist=col_dist_ri)
1166 CALL dbcsr_create(mat_z_lp, name=
'mat_Z_lP localized AA/AB', dist=dist_z, &
1167 matrix_type=dbcsr_type_no_symmetry, row_blk_size=row_size_grid, &
1168 col_blk_size=ri_blk_sizes)
1173 DO iatom = 1, bs_env%n_atom
1174 max_ao_size = max(max_ao_size, bs_env%i_ao_end_from_atom(iatom) - &
1175 bs_env%i_ao_start_from_atom(iatom) + 1)
1178 CALL timestop(handle)
1180 END SUBROUTINE prepare_z_lp_auto_ri
1199 SUBROUTINE common_z_lp_grid_available(bs_env, ri_rs_grid_points, &
1200 common_grid_available, have_fitted_columns)
1202 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: ri_rs_grid_points
1203 LOGICAL,
INTENT(OUT) :: common_grid_available, &
1206 CHARACTER(LEN=*),
PARAMETER :: routinen =
'common_Z_lP_grid_available'
1208 INTEGER :: ab_block, atom_a, atom_b, fit_atom, &
1209 handle, iatom, igrid, n_to_a, natom
1210 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: active_atom
1211 REAL(kind=
dp) :: cutoff_ri
1212 REAL(kind=
dp),
DIMENSION(3) :: center
1215 CALL timeset(routinen, handle)
1217 particle_set => bs_env%ri_rs%particle_set
1218 natom = bs_env%n_atom
1219 common_grid_available = .true.
1220 have_fitted_columns = .false.
1221 ALLOCATE (active_atom(natom))
1222 DO fit_atom = 1, natom
1223 IF (bs_env%auto_ri%sizes_opt_RI(fit_atom) == 0) cycle
1224 have_fitted_columns = .true.
1225 active_atom = .false.
1226 DO ab_block = 1, bs_env%auto_ri%AB_block_count
1227 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1228 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1229 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
1230 IF (.NOT. (fit_atom == atom_a .AND. n_to_a > 0) .AND. &
1231 .NOT. (fit_atom == atom_b .AND. &
1232 n_to_a < bs_env%auto_ri%AB_size_opt_RI(ab_block))) cycle
1233 active_atom(atom_a) = .true.
1234 IF (atom_b /= atom_a) active_atom(atom_b) = .true.
1237 center = particle_set(fit_atom)%r
1238 IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp)
THEN
1239 cutoff_ri = bs_env%ri_rs%cutoff_radius_ri_rs
1243 IF (.NOT. active_atom(iatom)) cycle
1244 cutoff_ri = max(cutoff_ri, bs_env%ri_metric%cutoff_radius + &
1245 bs_env%ri_rs%radius_ri_per_atom(iatom) + &
1246 norm2(center - particle_set(iatom)%r))
1250 DO igrid = 1,
SIZE(ri_rs_grid_points, 2)
1251 IF (norm2(ri_rs_grid_points(1:3, igrid) - center) > cutoff_ri)
THEN
1252 common_grid_available = .false.
1256 IF (.NOT. common_grid_available)
EXIT
1259 IF (norm2(particle_set(iatom)%r - center) > &
1260 bs_env%ri_rs%radius_ao_per_atom(iatom) + cutoff_ri)
THEN
1261 common_grid_available = .false.
1265 IF (.NOT. common_grid_available)
EXIT
1267 DEALLOCATE (active_atom)
1269 CALL timestop(handle)
1271 END SUBROUTINE common_z_lp_grid_available
1292 SUBROUTINE build_phi_on_complete_grid(bs_env, qs_kind_set, &
1293 ri_rs_grid_points, n_ao_total, local_grid_idx, ngrid, &
1294 phi_local, ao_col_map, n_ao_used)
1296 TYPE(
qs_kind_type),
DIMENSION(:),
POINTER :: qs_kind_set
1297 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: ri_rs_grid_points
1298 INTEGER,
INTENT(IN) :: n_ao_total
1299 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: local_grid_idx
1300 INTEGER,
INTENT(OUT) :: ngrid
1301 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
1302 INTENT(OUT) :: phi_local
1303 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: ao_col_map
1304 INTEGER,
INTENT(OUT) :: n_ao_used
1306 CHARACTER(LEN=*),
PARAMETER :: routinen =
'build_phi_on_complete_grid'
1308 INTEGER :: handle, iatom, igrid, reference_atom
1309 REAL(kind=
dp) :: cutoff_ri
1310 REAL(kind=
dp),
DIMENSION(3) :: center
1313 CALL timeset(routinen, handle)
1315 particle_set => bs_env%ri_rs%particle_set
1317 center = particle_set(reference_atom)%r
1319 DO igrid = 1,
SIZE(ri_rs_grid_points, 2)
1320 cutoff_ri = max(cutoff_ri, norm2(ri_rs_grid_points(1:3, igrid) - center))
1322 DO iatom = 1, bs_env%n_atom
1323 cutoff_ri = max(cutoff_ri, norm2(particle_set(iatom)%r - center))
1325 cutoff_ri = cutoff_ri + 1.0_dp
1327 CALL build_phi_on_sphere(bs_env, qs_kind_set, &
1328 ri_rs_grid_points, reference_atom, cutoff_ri, n_ao_total, &
1329 local_grid_idx, ngrid, phi_local, ao_col_map, n_ao_used, &
1332 CALL timestop(handle)
1334 END SUBROUTINE build_phi_on_complete_grid
1353 SUBROUTINE add_z_lp_columns(mat_Z_lP, z_block, local_grid_idx, n_local_grid, atom_index, &
1354 first_column, atom_block_size, r_blk_sizes, row_offset, row_dist, &
1358 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: z_block
1359 INTEGER,
DIMENSION(:),
INTENT(IN) :: local_grid_idx
1360 INTEGER,
INTENT(IN) :: n_local_grid, atom_index, first_column, &
1362 INTEGER,
DIMENSION(:),
INTENT(IN) :: r_blk_sizes, row_offset, row_dist
1363 INTEGER,
INTENT(IN) :: myprow
1364 REAL(kind=
dp),
INTENT(IN) :: eps_filter
1366 CHARACTER(LEN=*),
PARAMETER :: routinen =
'add_Z_lP_columns'
1368 INTEGER :: current_chunk_size, g_pt, handle, i_blk, &
1369 loc_ptr, ncolumn, r_end, r_start
1370 LOGICAL :: row_owned
1371 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: z_blk
1373 CALL timeset(routinen, handle)
1375 ncolumn =
SIZE(z_block, 2)
1376 cpassert(first_column > 0)
1377 cpassert(first_column + ncolumn - 1 <= atom_block_size)
1378 ALLOCATE (z_blk(maxval(r_blk_sizes), atom_block_size), source=0.0_dp)
1380 DO i_blk = 1,
SIZE(r_blk_sizes)
1381 r_start = row_offset(i_blk) + 1
1382 r_end = row_offset(i_blk) + r_blk_sizes(i_blk)
1383 current_chunk_size = r_blk_sizes(i_blk)
1384 row_owned = row_dist(i_blk) == myprow
1386 DO WHILE (loc_ptr <= n_local_grid)
1387 g_pt = local_grid_idx(loc_ptr)
1388 IF (g_pt > r_end)
EXIT
1390 z_blk(g_pt - r_start + 1, first_column:first_column + ncolumn - 1) = &
1391 z_block(loc_ptr, 1:ncolumn)
1393 loc_ptr = loc_ptr + 1
1395 IF (row_owned .AND. maxval(abs(z_blk(1:current_chunk_size, :))) > eps_filter)
THEN
1397 block=z_blk(1:current_chunk_size, :), summation=.true.)
1402 CALL timestop(handle)
1404 END SUBROUTINE add_z_lp_columns
1418 SUBROUTINE compute_nonzero_ao_grid_mask(bs_env, phi_val, ao_col_map, nonzero_ao)
1420 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: phi_val
1421 INTEGER,
DIMENSION(:),
INTENT(IN) :: ao_col_map
1422 LOGICAL,
ALLOCATABLE,
DIMENSION(:, :),
INTENT(OUT) :: nonzero_ao
1424 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_nonzero_AO_grid_mask'
1426 INTEGER :: col, first, handle, iatom, last, natom, &
1429 CALL timeset(routinen, handle)
1431 ngrid =
SIZE(phi_val, 1)
1432 natom = bs_env%n_atom
1433 ALLOCATE (nonzero_ao(ngrid, natom), source=.false.)
1438 first = ao_col_map(bs_env%i_ao_start_from_atom(iatom))
1439 IF (first == 0) cycle
1440 last = ao_col_map(bs_env%i_ao_end_from_atom(iatom))
1441 DO col = first, last
1443 nonzero_ao(point, iatom) = &
1444 nonzero_ao(point, iatom) .OR. phi_val(point, col) /= 0.0_dp
1450 CALL timestop(handle)
1451 END SUBROUTINE compute_nonzero_ao_grid_mask
1466 SUBROUTINE compute_d_lp_auto_ri_atom(bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid, iatom, &
1471 REAL(kind=
dp),
CONTIGUOUS,
DIMENSION(:, :), &
1472 INTENT(IN) :: phi_val
1473 INTEGER,
DIMENSION(:),
INTENT(IN) :: ao_col_map
1474 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: d_lp
1475 INTEGER,
INTENT(IN) :: n_grid, iatom
1476 REAL(kind=
dp),
CONTIGUOUS,
DIMENSION(:, :), &
1478 INTEGER,
INTENT(IN) :: max_ao_size
1480 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_d_lp_auto_ri_atom'
1481 INTEGER,
PARAMETER :: grid_chunk = 1024
1483 INTEGER :: jatom, katom, c, handle, i_thread, j, jk_idx, jsize, jstart, k, ksize, &
1484 kstart, l, l0, ncol, nri_ref, nthreads, ri, thread_id
1486 REAL(kind=
dp) :: pair_factor
1487 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: int_2d_prv, rho_chunk
1488 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: d_lp_threads, int_3c_prv
1491 LOGICAL,
ALLOCATABLE,
DIMENSION(:, :) :: nonzero_ao
1492 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: grid_index
1493 INTEGER :: n_grid_pair, grid_l, point
1494 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: grid_result
1496 CALL timeset(routinen, handle)
1497 ncol =
SIZE(u_pp, 2)
1498 nri_ref = get_ref_ri_size(bs_env, iatom)
1501 cpassert(
SIZE(d_lp, 1) == n_grid)
1502 cpassert(
SIZE(d_lp, 2) == ncol)
1503 cpassert(
SIZE(u_pp, 1) == nri_ref)
1504 ALLOCATE (d_lp_threads(n_grid, ncol, nthreads), source=0.0_dp)
1506 CALL compute_nonzero_ao_grid_mask(bs_env, phi_val, ao_col_map, nonzero_ao)
1522 ALLOCATE (int_3c_prv(max_ao_size, max_ao_size, ncol))
1523 ALLOCATE (int_2d_prv(max_ao_size*max_ao_size, ncol))
1524 ALLOCATE (rho_chunk(grid_chunk, max_ao_size*max_ao_size))
1525 ALLOCATE (grid_index(n_grid), grid_result(grid_chunk, ncol))
1528 DO jatom = 1, bs_env%n_atom
1529 DO katom = jatom, bs_env%n_atom
1530 jstart = ao_col_map(bs_env%i_ao_start_from_atom(jatom))
1531 kstart = ao_col_map(bs_env%i_ao_start_from_atom(katom))
1532 IF (jstart == 0 .OR. kstart == 0) cycle
1533 jsize = bs_env%i_ao_end_from_atom(jatom) - bs_env%i_ao_start_from_atom(jatom) + 1
1534 ksize = bs_env%i_ao_end_from_atom(katom) - bs_env%i_ao_start_from_atom(katom) + 1
1536 DO grid_l = 1, n_grid
1537 IF (.NOT. (nonzero_ao(grid_l, jatom) .AND. nonzero_ao(grid_l, katom))) cycle
1538 n_grid_pair = n_grid_pair + 1
1539 grid_index(n_grid_pair) = grid_l
1541 IF (n_grid_pair == 0) cycle
1542 int_3c_prv(1:jsize, 1:ksize, 1:ncol) = 0.0_dp
1543 CALL build_3c_integral_block_auto_ri_ctx( &
1544 int_3c_prv(1:jsize, 1:ksize, 1:ncol), ctx, ws, &
1545 atom_j=jatom, atom_k=katom, atom_i=iatom, &
1546 transform=u_pp, transform_row=1, screened=screened)
1551 jk_idx = (k - 1)*jsize + j
1552 int_2d_prv(jk_idx, ri) = int_3c_prv(j, k, ri)
1556 pair_factor = 1.0_dp
1557 IF (jatom /= katom) pair_factor = 2.0_dp
1558 DO l0 = 1, n_grid_pair, grid_chunk
1559 c = min(grid_chunk, n_grid_pair - l0 + 1)
1562 jk_idx = (k - 1)*jsize + j
1564 point = grid_index(l0 + l - 1)
1565 rho_chunk(l, jk_idx) = phi_val(point, jstart + j - 1)* &
1566 phi_val(point, kstart + k - 1)
1570 CALL dgemm(
'N',
'N', c, ncol, jsize*ksize, pair_factor, rho_chunk, grid_chunk, &
1571 int_2d_prv, max_ao_size*max_ao_size, 0.0_dp, &
1572 grid_result, grid_chunk)
1575 point = grid_index(l0 + l - 1)
1576 d_lp_threads(point, ri, thread_id) = &
1577 d_lp_threads(point, ri, thread_id) + grid_result(l, ri)
1588 DO i_thread = 1, nthreads
1589 d_lp(l, ri) = d_lp(l, ri) + d_lp_threads(l, ri, i_thread)
1594 DEALLOCATE (int_3c_prv, int_2d_prv, rho_chunk)
1595 DEALLOCATE (grid_index, grid_result)
1599 DEALLOCATE (d_lp_threads)
1601 DEALLOCATE (nonzero_ao)
1603 CALL timestop(handle)
1605 END SUBROUTINE compute_d_lp_auto_ri_atom
1622 SUBROUTINE compute_d_lp_auto_ri_atoms(bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid, &
1623 ri_coefficients, active_atom, max_ao_size, atom_j_mepos, &
1628 REAL(kind=
dp),
CONTIGUOUS,
DIMENSION(:, :), &
1629 INTENT(IN) :: phi_val
1630 INTEGER,
DIMENSION(:),
INTENT(IN) :: ao_col_map
1631 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: d_lp
1632 INTEGER,
INTENT(IN) :: n_grid
1633 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(IN) :: ri_coefficients
1634 LOGICAL,
DIMENSION(:),
INTENT(IN) :: active_atom
1635 INTEGER,
INTENT(IN) :: max_ao_size, atom_j_mepos, atom_j_stride
1637 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_d_lp_auto_ri_atoms'
1638 INTEGER,
PARAMETER :: grid_chunk = 1024
1640 INTEGER :: active_column, iatom, jatom, katom, c, handle, i_thread, j, jk_idx, jsize, &
1641 jstart, k, ksize, kstart, l, l0, &
1642 max_active, nactive, ncol, nri_ref, nthreads, ri, thread_id
1643 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: atom_ncol
1644 INTEGER,
ALLOCATABLE,
DIMENSION(:, :) :: atom_column
1645 LOGICAL :: any_integral, screened
1646 REAL(kind=
dp) :: pair_factor
1647 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: int_2d_prv, rho_chunk
1648 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: coefficient_compact, d_lp_threads, &
1649 int_3c_prv, int_3c_atom
1652 LOGICAL,
ALLOCATABLE,
DIMENSION(:, :) :: nonzero_ao
1653 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: grid_index
1654 INTEGER :: n_grid_pair, grid_l, point
1655 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: grid_result
1657 CALL timeset(routinen, handle)
1658 ncol =
SIZE(d_lp, 2)
1661 cpassert(
SIZE(d_lp, 1) == n_grid)
1662 cpassert(
SIZE(ri_coefficients, 2) == ncol)
1663 cpassert(
SIZE(ri_coefficients, 3) ==
SIZE(active_atom))
1664 ALLOCATE (atom_ncol(
SIZE(active_atom)), atom_column(ncol,
SIZE(active_atom)))
1667 DO iatom = 1,
SIZE(active_atom)
1668 IF (.NOT. active_atom(iatom)) cycle
1669 nri_ref = get_ref_ri_size(bs_env, iatom)
1671 IF (.NOT. any(ri_coefficients(1:nri_ref, ri, iatom) /= 0.0_dp)) cycle
1672 atom_ncol(iatom) = atom_ncol(iatom) + 1
1673 atom_column(atom_ncol(iatom), iatom) = ri
1676 max_active = maxval(atom_ncol)
1677 cpassert(max_active > 0)
1678 ALLOCATE (coefficient_compact(
SIZE(ri_coefficients, 1), max_active, &
1679 SIZE(active_atom)), source=0.0_dp)
1680 DO iatom = 1,
SIZE(active_atom)
1681 nri_ref = get_ref_ri_size(bs_env, iatom)
1682 DO active_column = 1, atom_ncol(iatom)
1683 ri = atom_column(active_column, iatom)
1684 coefficient_compact(1:nri_ref, active_column, iatom) = &
1685 ri_coefficients(1:nri_ref, ri, iatom)
1688 ALLOCATE (d_lp_threads(n_grid, ncol, nthreads), source=0.0_dp)
1690 CALL compute_nonzero_ao_grid_mask(bs_env, phi_val, ao_col_map, nonzero_ao)
1708 ALLOCATE (int_3c_prv(max_ao_size, max_ao_size, ncol))
1709 ALLOCATE (int_3c_atom(max_ao_size, max_ao_size, max_active))
1710 ALLOCATE (int_2d_prv(max_ao_size*max_ao_size, ncol))
1711 ALLOCATE (rho_chunk(grid_chunk, max_ao_size*max_ao_size))
1712 ALLOCATE (grid_index(n_grid), grid_result(grid_chunk, ncol))
1715 DO jatom = atom_j_mepos + 1, bs_env%n_atom, atom_j_stride
1716 DO katom = jatom, bs_env%n_atom
1717 jstart = ao_col_map(bs_env%i_ao_start_from_atom(jatom))
1718 kstart = ao_col_map(bs_env%i_ao_start_from_atom(katom))
1719 IF (jstart == 0 .OR. kstart == 0) cycle
1720 jsize = bs_env%i_ao_end_from_atom(jatom) - bs_env%i_ao_start_from_atom(jatom) + 1
1721 ksize = bs_env%i_ao_end_from_atom(katom) - bs_env%i_ao_start_from_atom(katom) + 1
1723 DO grid_l = 1, n_grid
1724 IF (.NOT. (nonzero_ao(grid_l, jatom) .AND. nonzero_ao(grid_l, katom))) cycle
1725 n_grid_pair = n_grid_pair + 1
1726 grid_index(n_grid_pair) = grid_l
1728 IF (n_grid_pair == 0) cycle
1729 int_3c_prv(1:jsize, 1:ksize, 1:ncol) = 0.0_dp
1730 any_integral = .false.
1731 DO iatom = 1,
SIZE(active_atom)
1732 IF (.NOT. active_atom(iatom)) cycle
1733 nri_ref = get_ref_ri_size(bs_env, iatom)
1734 nactive = atom_ncol(iatom)
1735 int_3c_atom(1:jsize, 1:ksize, 1:nactive) = 0.0_dp
1736 CALL build_3c_integral_block_auto_ri_ctx( &
1737 int_3c_atom(1:jsize, 1:ksize, 1:nactive), ctx, ws, &
1738 atom_j=jatom, atom_k=katom, atom_i=iatom, &
1739 transform=coefficient_compact(1:nri_ref, 1:nactive, iatom), &
1740 transform_row=1, screened=screened)
1741 IF (.NOT. screened)
THEN
1742 any_integral = .true.
1743 DO active_column = 1, nactive
1744 ri = atom_column(active_column, iatom)
1745 int_3c_prv(1:jsize, 1:ksize, ri) = &
1746 int_3c_prv(1:jsize, 1:ksize, ri) + &
1747 int_3c_atom(1:jsize, 1:ksize, active_column)
1751 IF (.NOT. any_integral) cycle
1756 jk_idx = (k - 1)*jsize + j
1757 int_2d_prv(jk_idx, ri) = int_3c_prv(j, k, ri)
1762 pair_factor = 1.0_dp
1763 IF (jatom /= katom) pair_factor = 2.0_dp
1764 DO l0 = 1, n_grid_pair, grid_chunk
1765 c = min(grid_chunk, n_grid_pair - l0 + 1)
1768 jk_idx = (k - 1)*jsize + j
1770 point = grid_index(l0 + l - 1)
1771 rho_chunk(l, jk_idx) = phi_val(point, jstart + j - 1)* &
1772 phi_val(point, kstart + k - 1)
1776 CALL dgemm(
'N',
'N', c, ncol, jsize*ksize, pair_factor, rho_chunk, grid_chunk, &
1777 int_2d_prv, max_ao_size*max_ao_size, 0.0_dp, &
1778 grid_result, grid_chunk)
1781 point = grid_index(l0 + l - 1)
1782 d_lp_threads(point, ri, thread_id) = &
1783 d_lp_threads(point, ri, thread_id) + grid_result(l, ri)
1794 DO i_thread = 1, nthreads
1795 d_lp(l, ri) = d_lp(l, ri) + d_lp_threads(l, ri, i_thread)
1800 DEALLOCATE (int_3c_prv, int_3c_atom, int_2d_prv, rho_chunk)
1801 DEALLOCATE (grid_index, grid_result)
1805 DEALLOCATE (coefficient_compact, d_lp_threads, atom_column, atom_ncol)
1807 DEALLOCATE (nonzero_ao)
1809 CALL timestop(handle)
1811 END SUBROUTINE compute_d_lp_auto_ri_atoms
1825 SUBROUTINE compute_d_lp_auto_ri_batch(bs_env, ctx, phi_val, ao_col_map, d_lp, n_grid, &
1826 max_ao_size, mepos, num_pe)
1829 REAL(kind=
dp),
CONTIGUOUS,
DIMENSION(:, :), &
1830 INTENT(IN) :: phi_val
1831 INTEGER,
DIMENSION(:),
INTENT(IN) :: ao_col_map
1832 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: d_lp
1833 INTEGER,
INTENT(IN) :: n_grid, max_ao_size, mepos, num_pe
1835 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_d_lp_auto_ri_batch'
1837 INTEGER :: column, handle, iatom, n_done, n_total, &
1839 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: global_map
1840 REAL(kind=
dp) :: item_start_time
1841 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: d_lp_batch, u_pp
1843 CALL timeset(routinen, handle)
1846 DO iatom = mepos + 1, bs_env%n_atom, num_pe
1847 n_total = n_total + 1
1851 DO iatom = mepos + 1, bs_env%n_atom, num_pe
1853 CALL collect_auto_ri_columns_for_atom(bs_env, iatom, u_pp, global_map)
1854 ncol_batch =
SIZE(global_map)
1855 IF (ncol_batch == 0)
THEN
1856 DEALLOCATE (u_pp, global_map)
1858 CALL print_z_lp_progress(bs_env, n_done, n_total, &
1863 ALLOCATE (d_lp_batch(n_grid, ncol_batch), source=0.0_dp)
1864 CALL compute_d_lp_auto_ri_atom(bs_env, ctx, phi_val, ao_col_map, d_lp_batch, &
1865 n_grid, iatom, u_pp, max_ao_size)
1866 DO column = 1, ncol_batch
1867 d_lp(:, global_map(column)) = d_lp(:, global_map(column)) + d_lp_batch(:, column)
1869 DEALLOCATE (u_pp, global_map, d_lp_batch)
1871 CALL print_z_lp_progress(bs_env, n_done, n_total, &
1874 CALL timestop(handle)
1876 END SUBROUTINE compute_d_lp_auto_ri_batch
1889 SUBROUTINE collect_auto_ri_columns_for_atom(bs_env, iatom, U_Pp, global_map)
1891 INTEGER,
INTENT(IN) :: iatom
1892 REAL(kind=
dp),
ALLOCATABLE,
INTENT(OUT) :: u_pp(:, :)
1893 INTEGER,
ALLOCATABLE,
INTENT(OUT) :: global_map(:)
1895 CHARACTER(LEN=*),
PARAMETER :: routinen =
'collect_auto_ri_columns_for_atom'
1897 INTEGER :: ab_block, atom_a, atom_b, column, global_column, handle, local_column, ncol, &
1898 ncol_batch, nri_ref, nri_ref_a, output_offset, row_first
1899 REAL(kind=
dp),
ALLOCATABLE :: u_pp_ab(:, :)
1901 CALL timeset(routinen, handle)
1904 DO ab_block = 1, bs_env%auto_ri%AB_block_count
1905 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1906 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1907 IF (iatom == atom_a .OR. iatom == atom_b)
THEN
1908 ncol_batch = ncol_batch + bs_env%auto_ri%AB_size_opt_RI(ab_block)
1912 nri_ref = get_ref_ri_size(bs_env, iatom)
1913 ALLOCATE (u_pp(nri_ref, ncol_batch), source=0.0_dp)
1914 ALLOCATE (global_map(ncol_batch))
1916 DO ab_block = 1, bs_env%auto_ri%AB_block_count
1917 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1918 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1919 IF (iatom /= atom_a .AND. iatom /= atom_b) cycle
1920 ncol = bs_env%auto_ri%AB_size_opt_RI(ab_block)
1921 CALL get_u_pp_ab(bs_env%auto_ri, ab_block, u_pp_ab)
1923 IF (iatom == atom_b .AND. atom_b /= atom_a)
THEN
1924 nri_ref_a = get_ref_ri_size(bs_env, atom_a)
1925 row_first = 1 + nri_ref_a
1927 u_pp(:, column + 1:column + ncol) = &
1929 row_first:row_first + nri_ref - 1, 1:ncol)
1931 DO local_column = 1, ncol
1932 IF (local_column <= bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block))
THEN
1933 output_offset = sum(bs_env%auto_ri%sizes_opt_RI(:atom_a - 1)) + &
1934 bs_env%auto_ri%AB_first_p_A(ab_block) - 1
1935 global_column = output_offset + local_column
1937 cpassert(atom_b /= atom_a)
1938 output_offset = sum(bs_env%auto_ri%sizes_opt_RI(:atom_b - 1)) + &
1939 bs_env%auto_ri%AB_first_p_B(ab_block) - 1
1940 global_column = output_offset + local_column - &
1941 bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
1943 global_map(column + local_column) = global_column
1945 column = column + ncol
1946 DEALLOCATE (u_pp_ab)
1948 cpassert(column == ncol_batch)
1950 CALL timestop(handle)
1952 END SUBROUTINE collect_auto_ri_columns_for_atom
1960 SUBROUTINE get_u_pp_ab(auto_ri, AB_block, U_Pp)
1962 INTEGER,
INTENT(IN) :: ab_block
1963 REAL(kind=
dp),
ALLOCATABLE,
INTENT(OUT) :: u_pp(:, :)
1965 INTEGER :: first, last, ncolumn, nrow
1967 nrow = auto_ri%AB_size_ref_RI(ab_block)
1968 ncolumn = auto_ri%AB_size_opt_RI(ab_block)
1969 first = auto_ri%U_Pp_AB_offset(ab_block)
1970 last = first + nrow*ncolumn - 1
1971 ALLOCATE (u_pp(nrow, ncolumn))
1972 u_pp(:, :) = reshape(auto_ri%U_Pp_AB(first:last), [nrow, ncolumn])
1974 END SUBROUTINE get_u_pp_ab
1984 SUBROUTINE compute_auto_ri_grid_radii(bs_env, radius)
1986 REAL(kind=
dp),
INTENT(OUT) :: radius(:)
1988 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_auto_ri_grid_radii'
1990 INTEGER :: a, ab_block, b, handle, n_to_a, ncol
1991 REAL(kind=
dp) :: cutoff, distance
1994 CALL timeset(routinen, handle)
1996 particle_set => bs_env%ri_rs%particle_set
1997 radius = bs_env%ri_rs%cutoff_radius_ri_rs
1998 IF (bs_env%ri_rs%cutoff_radius_ri_rs > 0.0_dp)
THEN
1999 CALL timestop(handle)
2003 cutoff = bs_env%ri_metric%cutoff_radius
2004 DO ab_block = 1, bs_env%auto_ri%AB_block_count
2005 a = bs_env%auto_ri%AB_atom_A(ab_block)
2006 b = bs_env%auto_ri%AB_atom_B(ab_block)
2007 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
2008 ncol = bs_env%auto_ri%AB_size_opt_RI(ab_block)
2009 IF (n_to_a > 0)
THEN
2010 radius(a) = max(radius(a), cutoff + bs_env%ri_rs%radius_ri_per_atom(a))
2012 distance = norm2(particle_set(a)%r - particle_set(b)%r)
2013 radius(a) = max(radius(a), cutoff + bs_env%ri_rs%radius_ri_per_atom(b) + distance)
2016 IF (n_to_a < ncol)
THEN
2018 distance = norm2(particle_set(b)%r - particle_set(a)%r)
2019 radius(b) = max(radius(b), cutoff + bs_env%ri_rs%radius_ri_per_atom(b), &
2020 cutoff + bs_env%ri_rs%radius_ri_per_atom(a) + distance)
2024 CALL timestop(handle)
2025 END SUBROUTINE compute_auto_ri_grid_radii
2043 SUBROUTINE compute_auto_ri_d_lp(qs_env, bs_env, ctx, grid, mat_phi, mat_rhs, max_ao_size)
2047 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: grid
2050 INTEGER,
INTENT(IN) :: max_ao_size
2052 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_auto_ri_d_lp'
2054 INTEGER :: ab_block, atom_a, atom_b, first, fit_atom, handle, handle_project, handle_rhs, l, &
2055 last, n_done, n_first_p_abs, n_to_a, n_total, n_union, nao, natom, ncol, ngrid, npcol, &
2057 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: ao_map, global_map, local_index, &
2058 row_offset, union_index
2059 INTEGER,
DIMENSION(:),
POINTER :: ab_row_dist, col_dist, &
2060 first_p_abs_per_atom, retained_size, &
2062 LOGICAL,
ALLOCATABLE,
DIMENSION(:) :: needed_fit_atom, union_mask
2063 REAL(kind=
dp) :: item_start_time, radius
2064 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: fit_radius
2065 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: column_map, phi, rhs, u_pp, union_grid
2071 TYPE(
qs_kind_type),
DIMENSION(:),
POINTER :: qs_kind_set
2073 CALL timeset(routinen, handle)
2074 CALL get_qs_env(qs_env, para_env=para_env, particle_set=particle_set, &
2075 qs_kind_set=qs_kind_set, cell=cell)
2076 natom = bs_env%n_atom
2077 CALL dbcsr_get_info(mat_phi, row_blk_size=row_size, distribution=dist_phi)
2079 ALLOCATE (first_p_abs_per_atom(natom), col_dist(natom), ab_row_dist(natom), &
2080 retained_size(natom), row_offset(
SIZE(row_size)))
2081 retained_size(:) = bs_env%auto_ri%sizes_opt_RI
2082 DO ri_atom = 1, natom
2083 first_p_abs_per_atom(ri_atom) = 0
2084 DO ab_block = 1, bs_env%auto_ri%AB_block_count
2085 IF (ri_atom == bs_env%auto_ri%AB_atom_A(ab_block) .OR. &
2086 ri_atom == bs_env%auto_ri%AB_atom_B(ab_block))
THEN
2087 first_p_abs_per_atom(ri_atom) = &
2088 first_p_abs_per_atom(ri_atom) + &
2089 bs_env%auto_ri%AB_size_opt_RI(ab_block)
2092 col_dist(ri_atom) = mod(ri_atom - 1, npcol)
2093 ab_row_dist(ri_atom) = mod(ri_atom - 1, nprow)
2096 DO l = 2,
SIZE(row_size)
2097 row_offset(l) = row_offset(l - 1) + row_size(l - 1)
2100 row_dist=row_dist, col_dist=col_dist)
2101 CALL dbcsr_create(ab_d_lp, name=
'AUTO_RI AA/AB d_lp', dist=dist_ab, &
2102 matrix_type=dbcsr_type_no_symmetry, row_blk_size=row_size, &
2103 col_blk_size=first_p_abs_per_atom)
2105 row_dist=ab_row_dist, col_dist=col_dist)
2106 CALL dbcsr_create(transform, name=
'AUTO_RI U_Pp', dist=dist_t, &
2107 matrix_type=dbcsr_type_no_symmetry, row_blk_size=first_p_abs_per_atom, &
2108 col_blk_size=retained_size)
2109 CALL dbcsr_create(mat_rhs, name=
'AUTO_RI optimized d_lp', dist=dist_ab, &
2110 matrix_type=dbcsr_type_no_symmetry, row_blk_size=row_size, &
2111 col_blk_size=retained_size)
2112 ALLOCATE (fit_radius(natom))
2113 CALL compute_auto_ri_grid_radii(bs_env, fit_radius)
2114 ALLOCATE (needed_fit_atom(natom), union_mask(
SIZE(grid, 2)))
2116 DO ri_atom = para_env%mepos + 1, natom, para_env%num_pe
2117 n_total = n_total + 1
2120 CALL timeset(routinen//
'_AB_d_lp', handle_rhs)
2121 DO ri_atom = para_env%mepos + 1, natom, para_env%num_pe
2123 needed_fit_atom = .false.
2124 DO ab_block = 1, bs_env%auto_ri%AB_block_count
2125 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
2126 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
2127 IF (ri_atom /= atom_a .AND. ri_atom /= atom_b) cycle
2128 n_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
2129 IF (n_to_a > 0) needed_fit_atom(atom_a) = .true.
2130 IF (n_to_a < bs_env%auto_ri%AB_size_opt_RI(ab_block))
THEN
2131 needed_fit_atom(atom_b) = .true.
2134 IF (.NOT. any(needed_fit_atom))
THEN
2136 CALL print_z_lp_progress(bs_env, n_done, n_total, &
2140 union_mask = .false.
2142 DO fit_atom = 1, natom
2143 IF (.NOT. needed_fit_atom(fit_atom)) cycle
2144 radius = max(radius, fit_radius(fit_atom) + &
2145 norm2(particle_set(fit_atom)%r - particle_set(ri_atom)%r))
2146 DO l = 1,
SIZE(grid, 2)
2147 IF (norm2(grid(:, l) - particle_set(fit_atom)%r) <= &
2148 fit_radius(fit_atom)) union_mask(l) = .true.
2151 n_union = count(union_mask)
2152 ALLOCATE (union_index(n_union), union_grid(3, n_union))
2154 DO l = 1,
SIZE(grid, 2)
2155 IF (.NOT. union_mask(l)) cycle
2156 n_union = n_union + 1
2157 union_index(n_union) = l
2158 union_grid(:, n_union) = grid(:, l)
2160 CALL build_phi_on_sphere(bs_env, qs_kind_set, union_grid, ri_atom, &
2161 radius + 1.0_dp, bs_env%i_ao_end_from_atom(natom), local_index, &
2162 ngrid, phi, ao_map, nao)
2163 local_index(1:ngrid) = union_index(local_index(1:ngrid))
2164 n_first_p_abs = first_p_abs_per_atom(ri_atom)
2165 CALL collect_auto_ri_columns_for_atom(bs_env, ri_atom, u_pp, global_map)
2166 cpassert(
SIZE(global_map) == n_first_p_abs)
2168 DO fit_atom = 1, natom
2169 ncol = retained_size(fit_atom)
2170 last = first + ncol - 1
2171 IF (any(global_map >= first .AND. global_map <= last))
THEN
2172 ALLOCATE (column_map(n_first_p_abs, ncol), source=0.0_dp)
2173 DO l = 1, n_first_p_abs
2174 IF (global_map(l) < first .OR. global_map(l) > last) cycle
2175 column_map(l, global_map(l) - first + 1) = 1.0_dp
2178 DEALLOCATE (column_map)
2182 ALLOCATE (rhs(ngrid, n_first_p_abs), source=0.0_dp)
2183 CALL compute_d_lp_auto_ri_atom(bs_env, ctx, phi, ao_map, rhs, ngrid, &
2184 ri_atom, u_pp, max_ao_size)
2186 row_size, row_offset, 0.0_dp)
2187 DEALLOCATE (rhs, u_pp, global_map, phi, ao_map, local_index, &
2188 union_grid, union_index)
2190 CALL print_z_lp_progress(bs_env, n_done, n_total, &
2195 CALL timestop(handle_rhs)
2196 CALL timeset(routinen//
'_transform', handle_project)
2197 CALL dbcsr_multiply(
'N',
'N', 1.0_dp, ab_d_lp, transform, 0.0_dp, &
2198 mat_rhs, filter_eps=0.0_dp)
2199 CALL timestop(handle_project)
2204 DEALLOCATE (first_p_abs_per_atom, retained_size, col_dist, ab_row_dist, row_offset, &
2205 fit_radius, needed_fit_atom, union_mask)
2206 CALL timestop(handle)
2207 END SUBROUTINE compute_auto_ri_d_lp
2217 SUBROUTINE extract_atom_d_lp(mat_rhs, atom_index, local_index, row_offset, rhs)
2219 INTEGER,
INTENT(IN) :: atom_index
2220 INTEGER,
DIMENSION(:),
INTENT(IN) :: local_index, row_offset
2221 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT) :: rhs
2223 CHARACTER(LEN=*),
PARAMETER :: routinen =
'extract_atom_d_lp'
2225 INTEGER :: handle, l, next_row, row
2227 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: block
2229 CALL timeset(routinen, handle)
2235 DO l = 1,
SIZE(rhs, 1)
2236 DO WHILE (next_row <=
SIZE(row_offset))
2237 IF (row_offset(next_row) >= local_index(l))
EXIT
2239 next_row = next_row + 1
2241 IF (.NOT. found)
NULLIFY (block)
2243 IF (
ASSOCIATED(block)) rhs(l, :) = block(local_index(l) - row_offset(row), :)
2246 CALL timestop(handle)
2247 END SUBROUTINE extract_atom_d_lp
2258 SUBROUTINE fit_auto_ri_z_lp(qs_env, bs_env, grid, mat_rhs, mat_z)
2261 REAL(kind=
dp),
INTENT(IN) :: grid(:, :)
2262 TYPE(
dbcsr_type),
INTENT(INOUT) :: mat_rhs, mat_z
2264 CHARACTER(LEN=*),
PARAMETER :: routinen =
'fit_auto_ri_z_lp'
2266 INTEGER :: atom_index, base, group_size, handle, &
2267 handle_gather, i, info, mypcol, n_big, &
2268 n_small, nao, natom, ncol, ngrid, &
2270 INTEGER,
ALLOCATABLE :: all_index(:), ao_map(:), big_list(:), &
2271 grid_size(:), local_index(:), &
2272 row_offset(:), small_list(:)
2273 INTEGER,
POINTER :: row_size(:)
2274 LOGICAL,
ALLOCATABLE :: single_rank(:)
2275 REAL(kind=
dp),
ALLOCATABLE :: atom_rhs(:, :), buffer(:, :), &
2276 diagonal(:), gram(:, :), &
2277 local_rhs(:, :), phi(:, :), radius(:)
2282 CALL timeset(routinen, handle)
2283 CALL get_qs_env(qs_env, para_env=para_env, qs_kind_set=qs_kinds)
2284 CALL dbcsr_get_info(mat_rhs, distribution=distribution, row_blk_size=row_size)
2286 ALLOCATE (column_env)
2287 CALL column_env%from_split(para_env, mypcol)
2288 natom = bs_env%n_atom
2289 ALLOCATE (radius(natom), all_index(
SIZE(grid, 2)), row_offset(
SIZE(row_size)))
2290 CALL compute_auto_ri_grid_radii(bs_env, radius)
2291 CALL classify_z_lp_atoms(bs_env, grid, radius, &
2292 bs_env%auto_ri%sizes_opt_RI, grid_size, &
2293 small_list, n_small, big_list, n_big, group_size)
2294 ALLOCATE (single_rank(natom), source=.false.)
2295 single_rank(small_list(:n_small)) = .true.
2296 DO i = 1,
SIZE(all_index)
2300 DO i = 2,
SIZE(row_size)
2301 row_offset(i) = row_offset(i - 1) + row_size(i - 1)
2303 DO base = mypcol + 1, natom, npcol*column_env%num_pe
2304 CALL timeset(routinen//
'_gather_rhs', handle_gather)
2305 DO slot = 0, column_env%num_pe - 1
2306 atom_index = base + slot*npcol
2307 IF (atom_index > natom)
EXIT
2308 IF (.NOT. single_rank(atom_index)) cycle
2309 ncol = bs_env%auto_ri%sizes_opt_RI(atom_index)
2310 IF (ncol == 0) cycle
2311 ALLOCATE (buffer(
SIZE(grid, 2), ncol))
2312 CALL extract_atom_d_lp(mat_rhs, atom_index, all_index, row_offset, buffer)
2313 CALL column_env%sum(buffer, slot)
2314 IF (column_env%mepos == slot)
THEN
2315 CALL move_alloc(buffer, atom_rhs)
2320 CALL timestop(handle_gather)
2321 atom_index = base + column_env%mepos*npcol
2322 IF (atom_index > natom) cycle
2323 IF (.NOT. single_rank(atom_index)) cycle
2324 ncol = bs_env%auto_ri%sizes_opt_RI(atom_index)
2325 IF (ncol == 0) cycle
2326 CALL build_phi_on_sphere(bs_env, qs_kinds, grid, atom_index, &
2327 radius(atom_index), bs_env%i_ao_end_from_atom(natom), &
2328 local_index, ngrid, phi, ao_map, nao)
2329 ALLOCATE (local_rhs(ngrid, ncol), diagonal(ngrid))
2331 local_rhs(i, :) = atom_rhs(local_index(i), :)
2333 DEALLOCATE (atom_rhs)
2336 CALL dpotrf(
'L', ngrid, gram, ngrid, info)
2338 CALL dpotrs(
'L', ngrid, ncol, gram, ngrid, local_rhs, ngrid, info)
2342 row_size, row_offset, 0.0_dp)
2343 DEALLOCATE (local_rhs, diagonal, gram, phi, ao_map, local_index)
2346 CALL fit_distributed_auto_ri_z_lp(qs_env, bs_env, grid, mat_rhs, mat_z, radius, &
2347 big_list(:n_big), group_size, row_size, row_offset, &
2350 DEALLOCATE (radius, all_index, row_offset, single_rank, grid_size, small_list, big_list)
2351 CALL column_env%free()
2352 DEALLOCATE (column_env)
2354 CALL timestop(handle)
2355 END SUBROUTINE fit_auto_ri_z_lp
2373 SUBROUTINE fit_distributed_auto_ri_z_lp(qs_env, bs_env, grid, mat_rhs, mat_z, radius, &
2374 atom_list, group_size, row_size, row_offset, &
2378 REAL(kind=
dp),
INTENT(IN) :: grid(:, :)
2379 TYPE(
dbcsr_type),
INTENT(INOUT) :: mat_rhs, mat_z
2380 REAL(kind=
dp),
INTENT(IN) :: radius(:)
2381 INTEGER,
INTENT(IN) :: atom_list(:), group_size, row_size(:), &
2382 row_offset(:), all_index(:)
2384 CHARACTER(LEN=*),
PARAMETER :: routinen =
'fit_distributed_auto_ri_z_lp'
2386 INTEGER :: atom_index, base, handle, i, info, &
2387 my_group, nao, ncol, ngrid, ngroups, &
2389 INTEGER,
ALLOCATABLE :: ao_map(:), local_index(:)
2390 REAL(kind=
dp),
ALLOCATABLE :: atom_rhs(:, :), buffer(:, :), &
2391 diagonal(:), local_rhs(:, :), phi(:, :)
2398 CALL timeset(routinen, handle)
2399 CALL get_qs_env(qs_env, para_env=para_env, qs_kind_set=qs_kinds)
2400 ngroups = max(1, para_env%num_pe/group_size)
2401 my_group = min(para_env%mepos/group_size, ngroups - 1)
2402 ALLOCATE (group_env)
2403 CALL group_env%from_split(para_env, my_group)
2404 NULLIFY (blacs_env, gram_struct, rhs_struct)
2406 DO base = 1,
SIZE(atom_list), ngroups
2407 DO slot = 0, ngroups - 1
2408 IF (base + slot >
SIZE(atom_list))
EXIT
2409 atom_index = atom_list(base + slot)
2410 ncol = bs_env%auto_ri%sizes_opt_RI(atom_index)
2411 IF (ncol == 0) cycle
2412 root = slot*group_size
2413 ALLOCATE (buffer(
SIZE(grid, 2), ncol))
2414 CALL extract_atom_d_lp(mat_rhs, atom_index, all_index, row_offset, buffer)
2415 CALL para_env%sum(buffer, root)
2416 IF (para_env%mepos == root)
THEN
2417 CALL move_alloc(buffer, atom_rhs)
2422 IF (base + my_group >
SIZE(atom_list)) cycle
2423 atom_index = atom_list(base + my_group)
2424 ncol = bs_env%auto_ri%sizes_opt_RI(atom_index)
2425 IF (ncol == 0) cycle
2426 IF (group_env%mepos /= 0)
ALLOCATE (atom_rhs(
SIZE(grid, 2), ncol))
2427 CALL group_env%bcast(atom_rhs, 0)
2428 CALL build_phi_on_sphere(bs_env, qs_kinds, grid, atom_index, &
2429 radius(atom_index), bs_env%i_ao_end_from_atom(bs_env%n_atom), &
2430 local_index, ngrid, phi, ao_map, nao)
2431 ALLOCATE (local_rhs(ngrid, ncol), diagonal(ngrid))
2433 local_rhs(i, :) = atom_rhs(local_index(i), :)
2435 DEALLOCATE (atom_rhs)
2439 bs_env%ri_rs%tikhonov, group_env, blacs_env, &
2440 gram_struct, rhs_struct, gram, rhs, info)
2443 IF (group_env%mepos == 0)
THEN
2445 row_size, row_offset, 0.0_dp)
2447 DEALLOCATE (local_rhs, diagonal, phi, ao_map, local_index)
2450 CALL group_env%free()
2451 DEALLOCATE (group_env)
2452 CALL timestop(handle)
2453 END SUBROUTINE fit_distributed_auto_ri_z_lp
2482 SUBROUTINE classify_z_lp_atoms(bs_env, ri_rs_grid_points, cutoff_ri_per_atom, ri_blk_sizes, &
2483 n_local_grid_atom, small_list, n_small, big_list, n_big, G)
2488 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: ri_rs_grid_points
2490 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: cutoff_ri_per_atom
2491 INTEGER,
DIMENSION(:),
INTENT(IN) :: ri_blk_sizes
2492 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: n_local_grid_atom, small_list, big_list
2493 INTEGER,
INTENT(OUT) :: n_small, n_big, g
2494 CHARACTER(LEN=*),
PARAMETER :: routinen =
'classify_z_lp_atoms'
2499 REAL(kind=
dp),
PARAMETER :: mem_safety = 0.8_dp
2503 REAL(kind=
dp),
PARAMETER :: scalapack_loc_limit = 2.0e9_dp
2505 INTEGER :: g_atom, g_int32, g_int32_max, l, &
2506 n_ao_used_atom, n_grid_total, &
2507 n_local_grid, natom, nthreads_cls, &
2509 LOGICAL :: auto_mode
2510 REAL(kind=
dp) :: budget_bytes, cutoff_ri, dlp_bytes, &
2511 mem_avail_gb, ng, nri, peak_bytes, &
2513 REAL(kind=
dp),
DIMENSION(3) :: pos_p
2517 CALL timeset(routinen, handle)
2519 para_env => bs_env%para_env
2520 particle_set => bs_env%ri_rs%particle_set
2521 natom = bs_env%n_atom
2522 n_grid_total =
SIZE(ri_rs_grid_points, 2)
2527 ALLOCATE (n_local_grid_atom(natom), small_list(natom), big_list(natom))
2528 DO p_loop_atom = 1, natom
2529 pos_p(:) = particle_set(p_loop_atom)%r(:)
2530 cutoff_ri = cutoff_ri_per_atom(p_loop_atom)
2532 DO l = 1, n_grid_total
2533 IF (sum((ri_rs_grid_points(1:3, l) - pos_p(1:3))**2) <= cutoff_ri**2)
THEN
2534 n_local_grid = n_local_grid + 1
2537 n_local_grid_atom(p_loop_atom) = n_local_grid
2545 auto_mode = (bs_env%ri_rs%n_procs_per_atom_z_lp <= 0)
2547 budget_bytes = mem_safety*mem_avail_gb*1.0e9_dp
2554 IF (bs_env%ri_rs%n_procs_per_atom_z_lp == 1)
THEN
2556 DO p_loop_atom = 1, natom
2557 n_small = n_small + 1
2558 small_list(n_small) = p_loop_atom
2560 ELSE IF (mem_avail_gb <= 0.0_dp)
THEN
2563 IF (bs_env%unit_nr > 0)
THEN
2564 cpwarn(
"RI-RS Z_lP: no meminfo; single-rank solve for all atoms")
2566 DO p_loop_atom = 1, natom
2567 n_small = n_small + 1
2568 small_list(n_small) = p_loop_atom
2572 DO p_loop_atom = 1, natom
2573 ng = real(n_local_grid_atom(p_loop_atom),
dp)
2574 g_int32_max = max(g_int32_max, ceiling(ng*ng/scalapack_loc_limit))
2576 big_list(n_big) = p_loop_atom
2578 g = min(bs_env%ri_rs%n_procs_per_atom_z_lp, para_env%num_pe)
2579 IF (g < g_int32_max)
THEN
2580 g = min(g_int32_max, para_env%num_pe)
2581 IF (bs_env%unit_nr > 0)
THEN
2582 cpwarn(
"RI-RS Z_lP: raised G to avoid ScaLAPACK overflow")
2589 DO p_loop_atom = 1, natom
2590 ng = real(n_local_grid_atom(p_loop_atom),
dp)
2591 nri = real(ri_blk_sizes(p_loop_atom),
dp)
2592 CALL get_n_ao_in_sphere(bs_env, p_loop_atom, &
2593 cutoff_ri_per_atom(p_loop_atom), n_ao_used_atom)
2594 phi_bytes = 8.0_dp*ng*real(n_ao_used_atom,
dp)
2595 dlp_bytes = 8.0_dp*ng*nri*real(1 + nthreads_cls,
dp)
2596 peak_bytes = 8.0_dp*ng*ng + phi_bytes + dlp_bytes
2597 IF (peak_bytes <= budget_bytes)
THEN
2598 n_small = n_small + 1
2599 small_list(n_small) = p_loop_atom
2602 big_list(n_big) = p_loop_atom
2605 g_int32 = ceiling(ng*ng/scalapack_loc_limit)
2606 g_int32_max = max(g_int32_max, g_int32)
2607 g_atom = max(g_atom, g_int32, &
2608 ceiling(8.0_dp*ng*ng/max(budget_bytes - phi_bytes - dlp_bytes, 1.0_dp)))
2614 IF (g_atom > para_env%num_pe)
THEN
2615 CALL cp_abort(__location__, &
2616 "RI-RS Z_lP: an atom is too large to fit even when "// &
2617 "distributed over all ranks. Add nodes, use fewer MPI ranks "// &
2618 "per node, lower CUTOFF_RADIUS_RL_RI, or raise EPS_FILTER "// &
2619 "for more grid screening.")
2621 g = min(max(g_atom, 2), para_env%num_pe)
2625 g = min(bs_env%ri_rs%n_procs_per_atom_z_lp, para_env%num_pe)
2626 IF (g < g_int32_max)
THEN
2627 g = min(g_int32_max, para_env%num_pe)
2628 IF (bs_env%unit_nr > 0)
THEN
2629 cpwarn(
"RI-RS Z_lP: raised G to avoid ScaLAPACK overflow")
2631 ELSE IF (g < g_atom .AND. bs_env%unit_nr > 0)
THEN
2632 cpwarn(
"RI-RS Z_lP: N_PROCS_PER_ATOM_Z_LP too small for the largest atom")
2638 CALL timestop(handle)
2640 END SUBROUTINE classify_z_lp_atoms
2649 SUBROUTINE get_n_ao_in_sphere(bs_env, atom_P, cutoff_ri, n_ao_used)
2652 INTEGER,
INTENT(IN) :: atom_p
2653 REAL(kind=
dp),
INTENT(IN) :: cutoff_ri
2654 INTEGER,
INTENT(OUT) :: n_ao_used
2656 CHARACTER(LEN=*),
PARAMETER :: routinen =
'get_n_ao_in_sphere'
2658 INTEGER :: handle, ri_atom
2661 CALL timeset(routinen, handle)
2663 particle_set => bs_env%ri_rs%particle_set
2665 DO ri_atom = 1, bs_env%n_atom
2666 IF (norm2(particle_set(ri_atom)%r(:) - particle_set(atom_p)%r(:)) > &
2667 bs_env%ri_rs%radius_ao_per_atom(ri_atom) + cutoff_ri) cycle
2668 n_ao_used = n_ao_used + bs_env%i_ao_end_from_atom(ri_atom) - &
2669 bs_env%i_ao_start_from_atom(ri_atom) + 1
2672 CALL timestop(handle)
2674 END SUBROUTINE get_n_ao_in_sphere
2691 SUBROUTINE build_phi_on_sphere(bs_env, qs_kind_set, ri_rs_grid_points, &
2692 atom_P, cutoff_ri, n_ao_total, local_grid_idx, n_local_grid, &
2693 phi_local, ao_col_map, n_ao_used, center)
2696 TYPE(
qs_kind_type),
DIMENSION(:),
POINTER :: qs_kind_set
2697 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: ri_rs_grid_points
2698 INTEGER,
INTENT(IN) :: atom_p
2699 REAL(kind=
dp),
INTENT(IN) :: cutoff_ri
2700 INTEGER,
INTENT(IN) :: n_ao_total
2701 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: local_grid_idx
2702 INTEGER,
INTENT(OUT) :: n_local_grid
2703 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2704 INTENT(OUT) :: phi_local
2705 INTEGER,
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: ao_col_map
2706 INTEGER,
INTENT(OUT) :: n_ao_used
2707 REAL(kind=
dp),
DIMENSION(3),
INTENT(IN),
OPTIONAL :: center
2709 CHARACTER(LEN=*),
PARAMETER :: routinen =
'build_phi_on_sphere'
2711 INTEGER :: col_end, col_start, handle, j, k, l, &
2712 loc_idx, n_grid_total, n_keep, ri_atom
2713 REAL(kind=
dp) :: d_sp, dist, r2_threshold
2714 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: w_pt
2715 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: phi_keep, sphere_grid
2716 REAL(kind=
dp),
DIMENSION(3) :: pos_p
2720 CALL timeset(routinen, handle)
2722 cell => bs_env%ri_rs%cell
2723 particle_set => bs_env%ri_rs%particle_set
2724 n_grid_total =
SIZE(ri_rs_grid_points, 2)
2725 IF (
PRESENT(center))
THEN
2726 pos_p(:) = center(:)
2728 pos_p(:) = particle_set(atom_p)%r(:)
2732 DO l = 1, n_grid_total
2733 dist = sqrt(sum((ri_rs_grid_points(1:3, l) - pos_p(1:3))**2))
2734 IF (dist <= cutoff_ri) n_local_grid = n_local_grid + 1
2737 ALLOCATE (local_grid_idx(n_local_grid))
2740 DO l = 1, n_grid_total
2741 dist = sqrt(sum((ri_rs_grid_points(1:3, l) - pos_p(1:3))**2))
2742 IF (dist <= cutoff_ri)
THEN
2743 n_local_grid = n_local_grid + 1
2744 local_grid_idx(n_local_grid) = l
2748 ALLOCATE (sphere_grid(3, n_local_grid))
2749 DO loc_idx = 1, n_local_grid
2750 sphere_grid(:, loc_idx) = ri_rs_grid_points(:, local_grid_idx(loc_idx))
2754 ALLOCATE (ao_col_map(n_ao_total))
2757 DO ri_atom = 1, bs_env%n_atom
2758 d_sp = norm2(particle_set(ri_atom)%r(:) - pos_p(:))
2759 IF (d_sp > bs_env%ri_rs%radius_ao_per_atom(ri_atom) + cutoff_ri) cycle
2761 DO j = bs_env%i_ao_start_from_atom(ri_atom), bs_env%i_ao_end_from_atom(ri_atom)
2762 n_ao_used = n_ao_used + 1
2763 ao_col_map(j) = n_ao_used
2767 ALLOCATE (phi_local(n_local_grid, n_ao_used))
2770 DO ri_atom = 1, bs_env%n_atom
2771 d_sp = norm2(particle_set(ri_atom)%r(:) - pos_p(:))
2772 IF (d_sp > bs_env%ri_rs%radius_ao_per_atom(ri_atom) + cutoff_ri) cycle
2774 col_start = ao_col_map(bs_env%i_ao_start_from_atom(ri_atom))
2775 col_end = ao_col_map(bs_env%i_ao_end_from_atom(ri_atom))
2778 IF (bs_env%ri_rs%cutoff_radius_ri_ao > 0.0_dp)
THEN
2779 r2_threshold = bs_env%ri_rs%cutoff_radius_ri_ao**2
2781 r2_threshold = bs_env%ri_rs%radius_ao_per_atom(ri_atom)**2
2785 ri_atom, particle_set, qs_kind_set, cell, &
2786 cutoff_squared=r2_threshold)
2789 DEALLOCATE (sphere_grid)
2791 IF (n_local_grid > 0)
THEN
2792 ALLOCATE (w_pt(n_local_grid))
2796 DO l = 1, n_local_grid
2799 w_pt(l) = max(w_pt(l), abs(phi_local(l, j)))
2803 n_keep = count(w_pt > bs_env%eps_filter)
2804 IF (n_keep < n_local_grid)
THEN
2805 ALLOCATE (phi_keep(n_keep, n_ao_used))
2807 DO l = 1, n_local_grid
2808 IF (w_pt(l) > bs_env%eps_filter)
THEN
2810 phi_keep(k, :) = phi_local(l, :)
2811 local_grid_idx(k) = local_grid_idx(l)
2814 CALL move_alloc(phi_keep, phi_local)
2815 n_local_grid = n_keep
2820 CALL timestop(handle)
2822 END SUBROUTINE build_phi_on_sphere
2843 SUBROUTINE build_3c_integral_block_auto_ri_ctx(int_3c, ctx, ws, atom_j, atom_k, atom_i, &
2844 transform, transform_row, screened)
2845 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(INOUT) :: int_3c
2848 INTEGER,
INTENT(IN) :: atom_j, atom_k, atom_i
2849 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: transform
2850 INTEGER,
INTENT(IN) :: transform_row
2851 LOGICAL,
INTENT(OUT),
OPTIONAL :: screened
2853 CHARACTER(LEN=*),
PARAMETER :: routinen =
'build_3c_integral_block_auto_ri_ctx'
2855 INTEGER :: handle_contract, handle_eri, ikind, iset, jkind, jset, kkind, kset, l, ncoi, &
2856 ncoj, ncok, ncol, npgf_group, nseti, nsetj, nsetk, primitive_first, sgfi, sgfj, sgfk
2857 INTEGER,
DIMENSION(:),
POINTER :: lmax_i, lmax_j, lmax_k, lmin_i, lmin_j, &
2858 lmin_k, npgfi, npgfj, npgfk, nsgfi, &
2860 INTEGER,
DIMENSION(:, :),
POINTER :: first_sgf_i, first_sgf_j, first_sgf_k
2861 REAL(kind=
dp) :: dij, dik, djk, group_radius, &
2862 kind_radius_i, kind_radius_j, &
2863 kind_radius_k, sijk_ext
2864 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: rpgf_group, zet_group
2865 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: spi_group
2866 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: sijk, sijk_contr
2867 REAL(kind=
dp),
DIMENSION(3) :: ri, rij, rik, rj, rjk, rk
2868 REAL(kind=
dp),
DIMENSION(:),
POINTER :: set_radius_i, set_radius_j, set_radius_k
2869 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: rpgf_i, rpgf_j, rpgf_k, zeti, zetj, zetk
2871 IF (
PRESENT(screened)) screened = .false.
2872 ri =
pbc(ctx%particle_set(atom_i)%r(1:3), ctx%cell)
2873 rj =
pbc(ctx%particle_set(atom_j)%r(1:3), ctx%cell)
2874 rk =
pbc(ctx%particle_set(atom_k)%r(1:3), ctx%cell)
2882 ikind = ctx%kind_of(atom_i)
2883 jkind = ctx%kind_of(atom_j)
2884 kkind = ctx%kind_of(atom_k)
2885 CALL get_gto_basis_set(ctx%basis_i(ikind)%gto_basis_set, first_sgf=first_sgf_i, &
2886 lmax=lmax_i, lmin=lmin_i, npgf=npgfi, nset=nseti, &
2887 nsgf_set=nsgfi, pgf_radius=rpgf_i, set_radius=set_radius_i, &
2888 zet=zeti, kind_radius=kind_radius_i)
2889 CALL get_gto_basis_set(ctx%basis_j(jkind)%gto_basis_set, first_sgf=first_sgf_j, &
2890 lmax=lmax_j, lmin=lmin_j, npgf=npgfj, nset=nsetj, &
2891 nsgf_set=nsgfj, pgf_radius=rpgf_j, set_radius=set_radius_j, &
2892 zet=zetj, kind_radius=kind_radius_j)
2893 CALL get_gto_basis_set(ctx%basis_k(kkind)%gto_basis_set, first_sgf=first_sgf_k, &
2894 lmax=lmax_k, lmin=lmin_k, npgf=npgfk, nset=nsetk, &
2895 nsgf_set=nsgfk, pgf_radius=rpgf_k, set_radius=set_radius_k, &
2896 zet=zetk, kind_radius=kind_radius_k)
2898 IF (kind_radius_j + kind_radius_i + ctx%dr_ij < dij .OR. &
2899 kind_radius_j + kind_radius_k + ctx%dr_jk < djk .OR. &
2900 kind_radius_k + kind_radius_i + ctx%dr_ik < dik)
THEN
2901 IF (
PRESENT(screened)) screened = .true.
2905 ncol =
SIZE(transform, 2)
2906 cpassert(
SIZE(int_3c, 3) == ncol)
2909 group_radius = 0.0_dp
2911 IF (lmin_i(iset) /= l .OR. lmax_i(iset) /= l) cycle
2912 npgf_group = npgf_group + npgfi(iset)
2913 group_radius = max(group_radius, set_radius_i(iset))
2915 IF (npgf_group == 0) cycle
2916 ncoi = npgf_group*
ncoset(l)
2917 ALLOCATE (zet_group(npgf_group), rpgf_group(npgf_group))
2918 ALLOCATE (spi_group(ncoi, ncol), source=0.0_dp)
2921 IF (lmin_i(iset) /= l .OR. lmax_i(iset) /= l) cycle
2922 zet_group(primitive_first:primitive_first + npgfi(iset) - 1) = &
2923 zeti(1:npgfi(iset), iset)
2924 rpgf_group(primitive_first:primitive_first + npgfi(iset) - 1) = &
2925 rpgf_i(1:npgfi(iset), iset)
2926 sgfi = first_sgf_i(1, iset)
2927 spi_group((primitive_first - 1)*
ncoset(l) + 1: &
2928 (primitive_first + npgfi(iset) - 1)*
ncoset(l), :) = &
2929 matmul(ctx%spi(iset, ikind)%array, &
2930 transform(transform_row + sgfi - 1: &
2931 transform_row + sgfi + nsgfi(iset) - 2, :))
2932 primitive_first = primitive_first + npgfi(iset)
2936 IF (set_radius_j(jset) + group_radius + ctx%dr_ij < dij) cycle
2938 IF (set_radius_j(jset) + set_radius_k(kset) + ctx%dr_jk < djk) cycle
2939 IF (set_radius_k(kset) + group_radius + ctx%dr_ik < dik) cycle
2940 ncoj = npgfj(jset)*
ncoset(lmax_j(jset))
2941 ncok = npgfk(kset)*
ncoset(lmax_k(kset))
2942 sgfj = first_sgf_j(1, jset)
2943 sgfk = first_sgf_k(1, kset)
2944 IF (ncoj*ncok*ncoi <= 0) cycle
2945 ALLOCATE (sijk(ncoj, ncok, ncoi), source=0.0_dp)
2946 CALL timeset(routinen//
'_eri', handle_eri)
2948 lmin_j(jset), lmax_j(jset), npgfj(jset), zetj(:, jset), &
2949 rpgf_j(:, jset), rj, &
2950 lmin_k(kset), lmax_k(kset), npgfk(kset), zetk(:, kset), &
2951 rpgf_k(:, kset), rk, l, l, npgf_group, zet_group, &
2952 rpgf_group, ri, djk, dij, dik, ws%lib, ctx%potential_parameter, &
2953 int_abc_ext=sijk_ext)
2954 CALL timestop(handle_eri)
2955 ALLOCATE (sijk_contr(nsgfj(jset), nsgfk(kset), ncol))
2956 CALL timeset(routinen//
'_contract', handle_contract)
2958 ctx%spk(kset, kkind)%array, spi_group, ncoj, ncok, ncoi, &
2959 nsgfj(jset), nsgfk(kset), ncol, ws%cpp_buffer, ws%ccp_buffer)
2960 CALL timestop(handle_contract)
2962 int_3c(sgfj:sgfj + nsgfj(jset) - 1, sgfk:sgfk + nsgfk(kset) - 1, :) = &
2963 int_3c(sgfj:sgfj + nsgfj(jset) - 1, sgfk:sgfk + nsgfk(kset) - 1, :) + &
2965 DEALLOCATE (sijk_contr)
2968 DEALLOCATE (zet_group, rpgf_group, spi_group)
2971 END SUBROUTINE build_3c_integral_block_auto_ri_ctx
2979 INTEGER FUNCTION get_ref_ri_size(bs_env, iatom)
RESULT(n)
2981 INTEGER,
INTENT(IN) :: iatom
2985 ikind = bs_env%ri_rs%particle_set(iatom)%atomic_kind%kind_number
2986 n = bs_env%basis_set_RI(ikind)%gto_basis_set%nsgf
2988 END FUNCTION get_ref_ri_size
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...
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.
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
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 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 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 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.
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.
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 in either the standard tabulated or automatically generated RI basis set.
Utility method to build 3-center integrals for small cell GW.
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_ws_create(ws, ctx)
Creates a per-thread 3c workspace: libint object + LIBXSMM contraction buffers.
subroutine, public gw_3c_ws_release(ws)
Releases a per-thread 3c workspace.
subroutine, public gw_3c_ctx_release(ctx)
Releases the shared 3c-integral context.
subroutine, public gw_3c_ctx_create(ctx, qs_env, potential_parameter, basis_j, basis_k, basis_i)
Builds the shared 3c-integral context: screening radii, basis maxima, contracted sphi tables,...
Defines the basic variable types.
integer, parameter, public dp
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.
subroutine, public m_flush(lunit)
flushes units if the &GLOBAL flag is set accordingly
real(kind=dp) function, public m_walltime()
returns time from a real-time clock, protected against rolling early/easily
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:
real(kind=dp), parameter, public angstrom
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.
Shared RI-RS grid I/O and contracted-Gaussian evaluation utilities.
subroutine, public evaluate_ao_on_points(phi, grid_points, atom_index, particle_set, qs_kind_set, cell, dphi, cutoff_squared)
Evaluate contracted spherical AOs, and optionally their grid-coordinate derivatives.
All kind of helpful little routines.
Provides all information about an atomic kind.
Type defining parameters related to the simulation cell.
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of 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.