57 USE ieee_arithmetic,
ONLY: ieee_is_finite
80#include "base/base_uses.f90"
85 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'gw_auto_ri_generate_RI_basis'
88 REAL(KIND=
dp),
PARAMETER :: reference_m_eigenval_threshold = 1.0e-10_dp
89 REAL(KIND=
dp),
PARAMETER :: optimized_m_eigenval_threshold = 1.0e-6_dp
91 REAL(KIND=
dp),
PARAMETER :: relative_target_eigenval_threshold = 1.0e-12_dp
92 REAL(KIND=
dp),
PARAMETER :: ab_absolute_target_eigenval_threshold = 1.0e-12_dp
93 REAL(KIND=
dp),
PARAMETER :: negative_eigenval_tolerance = 1.0e-10_dp
97 TYPE ab_block_list_type
98 INTEGER,
ALLOCATABLE :: block(:)
99 INTEGER,
ALLOCATABLE :: first_p_AB(:)
100 INTEGER,
ALLOCATABLE :: first_p_atom(:)
101 INTEGER,
ALLOCATABLE :: size_opt_RI(:)
102 END TYPE ab_block_list_type
104 TYPE optimized_atom_u_type
105 INTEGER,
ALLOCATABLE :: ref_atom(:)
106 INTEGER,
ALLOCATABLE :: first_P(:)
107 REAL(KIND=
dp),
ALLOCATABLE :: u_pp(:, :)
108 END TYPE optimized_atom_u_type
193 CHARACTER(LEN=*),
PARAMETER :: routinen =
'generate_auto_ri_basis'
196 REAL(kind=
dp) :: time_start
197 REAL(kind=
dp),
ALLOCATABLE :: u_pp_a(:, :, :)
199 CALL timeset(routinen, handle)
204 CALL compute_aa_optimized_ri_basis(bs_env, u_pp_a)
207 CALL compute_ab_optimized_ri_basis(qs_env, bs_env, u_pp_a)
211 CALL compute_m_pq_inv_and_v_pq(qs_env, bs_env)
214 CALL print_auto_ri_summary(bs_env, time_start)
216 CALL timestop(handle)
238 SUBROUTINE compute_aa_optimized_ri_basis(bs_env, U_Pp_A)
240 REAL(kind=
dp),
ALLOCATABLE,
INTENT(OUT) :: u_pp_a(:, :, :)
242 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_AA_optimized_RI_basis'
244 INTEGER :: handle, iatom, ikind, max_nao_kind, max_nri_kind, nao_kind, natom, nkind, &
245 nri_kind, ri_size_opt_aa_requested, root_rank
246 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: kind_of_atom, sizes_opt_ri_aa
247 REAL(kind=
dp) :: target_norm
248 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eigenval
249 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: b_pq, eigenval_aa, m_pq, u_pp_a_atom
250 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: m_pq_by_kind
251 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :, :) :: int_3c
254 CALL timeset(routinen, handle)
258 CALL initialize_aa_optimization(bs_env, para_env, kind_of_atom, natom, nkind, &
259 max_nri_kind, ri_size_opt_aa_requested)
260 ALLOCATE (eigenval_aa(max_nri_kind, natom), source=0.0_dp)
261 ALLOCATE (sizes_opt_ri_aa(natom))
263 CALL initialize_auto_ri_integrals(bs_env)
264 max_nao_kind = maxval(bs_env%sizes_AO)
265 ALLOCATE (u_pp_a(max_nri_kind, max_nri_kind, natom), &
266 m_pq_by_kind(max_nri_kind, max_nri_kind, nkind), source=0.0_dp)
267 ALLOCATE (int_3c(max_nao_kind, max_nao_kind, max_nri_kind, nkind), source=0.0_dp)
271 nao_kind = bs_env%basis_set_AO(ikind)%gto_basis_set%nsgf
272 nri_kind = bs_env%basis_set_RI(ikind)%gto_basis_set%nsgf
273 CALL compute_int_3c( &
274 ao_basis=bs_env%basis_set_AO(ikind)%gto_basis_set, &
275 ri_basis=bs_env%basis_set_RI(ikind)%gto_basis_set, &
276 potential=bs_env%ri_metric, m_pq=m_pq, &
277 int_3c=int_3c(1:nao_kind, 1:nao_kind, 1:nri_kind, ikind))
278 CALL add_ri_metric_regularization(bs_env%basis_set_RI(ikind)%gto_basis_set, &
279 bs_env%regularization_RI, m_pq)
280 m_pq_by_kind(1:nri_kind, 1:nri_kind, ikind) = m_pq
284 bs_env%auto_ri%sizes_opt_RI = 0
286 root_rank =
modulo(iatom - 1, para_env%num_pe)
287 ikind = kind_of_atom(iatom)
288 nri_kind = bs_env%basis_set_RI(ikind)%gto_basis_set%nsgf
289 nao_kind = bs_env%sizes_AO(iatom)
290 ALLOCATE (m_pq(nri_kind, nri_kind))
291 m_pq(:, :) = m_pq_by_kind(1:nri_kind, 1:nri_kind, ikind)
293 CALL compute_b_pq_aa(bs_env, iatom, root_rank, &
294 int_3c(1:nao_kind, 1:nao_kind, 1:nri_kind, ikind), &
295 m_pq, b_pq, target_norm)
297 IF (root_rank /= para_env%mepos)
THEN
302 CALL solve_aa_eigenproblem(m_pq_by_kind(1:nri_kind, 1:nri_kind, ikind), &
303 b_pq, target_norm, u_pp_a_atom, eigenval)
304 eigenval_aa(1:
SIZE(u_pp_a_atom, 2), iatom) = eigenval(1:
SIZE(u_pp_a_atom, 2))
305 bs_env%auto_ri%sizes_opt_RI(iatom) =
SIZE(u_pp_a_atom, 2)
306 u_pp_a(1:
SIZE(u_pp_a_atom, 1), 1:
SIZE(u_pp_a_atom, 2), iatom) = u_pp_a_atom
307 DEALLOCATE (u_pp_a_atom, eigenval, b_pq)
309 CALL para_env%sum(bs_env%auto_ri%sizes_opt_RI)
310 CALL para_env%sum(u_pp_a)
311 CALL para_env%sum(eigenval_aa)
312 CALL select_ri_sizes(eigenval_aa, ri_size_opt_aa_requested, 1, sizes_opt_ri_aa)
313 bs_env%auto_ri%sizes_opt_RI(:) = sizes_opt_ri_aa
315 u_pp_a(:, sizes_opt_ri_aa(iatom) + 1:, iatom) = 0.0_dp
317 DEALLOCATE (int_3c, m_pq_by_kind)
319 CALL timestop(handle)
321 END SUBROUTINE compute_aa_optimized_ri_basis
341 SUBROUTINE initialize_aa_optimization(bs_env, para_env, kind_of_atom, &
342 natom, nkind, max_nRI_kind, &
343 RI_size_opt_AA_requested)
346 INTEGER,
ALLOCATABLE,
INTENT(OUT) :: kind_of_atom(:)
347 INTEGER,
INTENT(OUT) :: natom, nkind, max_nri_kind, &
348 ri_size_opt_aa_requested
350 CHARACTER(LEN=*),
PARAMETER :: routinen =
'initialize_AA_optimization'
352 INTEGER :: handle, ikind, ri_size_requested
353 INTEGER,
ALLOCATABLE :: sizes_ref_ri_by_kind(:)
355 CALL timeset(routinen, handle)
357 para_env => bs_env%para_env
358 natom = bs_env%n_atom
359 nkind =
SIZE(bs_env%basis_set_RI)
360 cpassert(
ASSOCIATED(bs_env%ri_rs%atomic_kind_set))
361 cpassert(
ASSOCIATED(bs_env%ri_rs%particle_set))
362 cpassert(
ASSOCIATED(para_env) .AND. natom > 0 .AND. nkind > 0)
363 cpassert(
ALLOCATED(bs_env%basis_set_AO))
364 cpassert(
ALLOCATED(bs_env%basis_set_RI))
365 cpassert(
SIZE(bs_env%basis_set_AO) == nkind)
366 cpassert(
SIZE(bs_env%basis_set_RI) == nkind)
367 cpassert(bs_env%do_gw_ri_rs)
368 cpassert(.NOT. bs_env%do_periodic)
372 kind_of=kind_of_atom)
373 ALLOCATE (bs_env%auto_ri%sizes_opt_RI(natom))
374 ALLOCATE (sizes_ref_ri_by_kind(nkind))
376 cpassert(
ASSOCIATED(bs_env%basis_set_AO(ikind)%gto_basis_set))
377 cpassert(
ASSOCIATED(bs_env%basis_set_RI(ikind)%gto_basis_set))
378 sizes_ref_ri_by_kind(ikind) = bs_env%basis_set_RI(ikind)%gto_basis_set%nsgf
380 max_nri_kind = maxval(sizes_ref_ri_by_kind)
381 ri_size_requested = nint( &
382 min(bs_env%auto_ri%ri_ao_ratio, &
383 REAL(sum(sizes_ref_ri_by_kind(kind_of_atom)),
dp)/ &
384 REAL(SUM(bs_env%sizes_AO),
dp))*
REAL(SUM(bs_env%sizes_AO),
dp))
385 ri_size_opt_aa_requested = max(natom, nint(0.5_dp*real(ri_size_requested,
dp)))
386 DEALLOCATE (sizes_ref_ri_by_kind)
388 CALL timestop(handle)
390 END SUBROUTINE initialize_aa_optimization
396 SUBROUTINE set_optimized_ri_basis_sizes(bs_env)
399 CHARACTER(LEN=*),
PARAMETER :: routinen =
'set_optimized_RI_basis_sizes'
403 CALL timeset(routinen, handle)
405 bs_env%sizes_RI(:) = bs_env%auto_ri%sizes_opt_RI
406 bs_env%auto_ri%ready = .true.
408 CALL timestop(handle)
410 END SUBROUTINE set_optimized_ri_basis_sizes
417 SUBROUTINE print_auto_ri_summary(bs_env, time_start)
419 REAL(kind=
dp),
INTENT(IN) :: time_start
421 CHARACTER(LEN=*),
PARAMETER :: routinen =
'print_auto_ri_summary'
423 INTEGER :: handle, ri_size_optimized, unit_nr
424 REAL(kind=
dp) :: elapsed
426 CALL timeset(routinen, handle)
428 ri_size_optimized = sum(bs_env%auto_ri%sizes_opt_RI)
430 CALL bs_env%para_env%max(elapsed)
431 unit_nr = bs_env%unit_nr
432 IF (unit_nr > 0)
THEN
433 WRITE (unit_nr,
'(A)')
' '
434 WRITE (unit_nr,
'(T2,A,T74,I9)') &
435 'AUTO_RI| Number of automatic RI functions for χ, ε, W:', ri_size_optimized
436 WRITE (unit_nr,
'(T2,A,T71,F8.1,A)') &
437 'AUTO_RI| Total RI basis optimization time:', elapsed,
' s'
440 CALL timestop(handle)
442 END SUBROUTINE print_auto_ri_summary
451 SUBROUTINE add_ri_metric_regularization(basis, regularization, M_PQ, offset)
454 REAL(kind=
dp),
INTENT(IN) :: regularization
455 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: m_pq
456 INTEGER,
INTENT(IN),
OPTIONAL :: offset
458 CHARACTER(LEN=*),
PARAMETER :: routinen =
'add_RI_metric_regularization'
460 INTEGER :: first, handle, i, iset, nset, start
461 INTEGER,
DIMENSION(:),
POINTER :: npgf, nsgf_set
462 INTEGER,
DIMENSION(:, :),
POINTER :: first_sgf
463 REAL(kind=
dp) :: shift
464 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: zet
466 CALL timeset(routinen, handle)
469 IF (
PRESENT(offset)) start = offset
471 nsgf_set=nsgf_set, zet=zet)
472 cpassert(start >= 0 .AND. start + basis%nsgf <=
SIZE(m_pq, 1))
473 cpassert(start + basis%nsgf <=
SIZE(m_pq, 2))
475 shift = regularization*max(1.0_dp, 1.0_dp/minval(zet(1:npgf(iset), iset)))
476 first = start + first_sgf(1, iset)
477 DO i = first, first + nsgf_set(iset) - 1
478 m_pq(i, i) = m_pq(i, i) + shift
482 CALL timestop(handle)
484 END SUBROUTINE add_ri_metric_regularization
494 SUBROUTINE copy_m_pq_aa_blocks(M_pq_local, M_pq_AA_local, row_indices, &
495 col_indices, sizes_RI)
496 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: m_pq_local
497 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(OUT) :: m_pq_aa_local
498 INTEGER,
DIMENSION(:),
INTENT(IN) :: row_indices, col_indices, sizes_ri
500 CHARACTER(LEN=*),
PARAMETER :: routinen =
'copy_M_pq_AA_blocks'
502 INTEGER :: handle, i, j, last_index
503 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: block_ends, col_atom, row_atom
505 CALL timeset(routinen, handle)
507 cpassert(
SIZE(m_pq_local, 1) ==
SIZE(row_indices))
508 cpassert(
SIZE(m_pq_local, 2) ==
SIZE(col_indices))
509 cpassert(all(shape(m_pq_aa_local) == shape(m_pq_local)))
510 cpassert(
SIZE(sizes_ri) > 0 .AND. all(sizes_ri > 0))
512 ALLOCATE (block_ends(
SIZE(sizes_ri)))
513 block_ends(1) = sizes_ri(1)
514 DO i = 2,
SIZE(sizes_ri)
515 block_ends(i) = block_ends(i - 1) + sizes_ri(i)
517 last_index = block_ends(
SIZE(block_ends))
518 cpassert(all(row_indices >= 1 .AND. row_indices <= last_index))
519 cpassert(all(col_indices >= 1 .AND. col_indices <= last_index))
521 ALLOCATE (row_atom(
SIZE(row_indices)), col_atom(
SIZE(col_indices)))
522 DO i = 1,
SIZE(row_indices)
523 row_atom(i) = m_pq_index_atom(row_indices(i), block_ends)
525 DO j = 1,
SIZE(col_indices)
526 col_atom(j) = m_pq_index_atom(col_indices(j), block_ends)
529 m_pq_aa_local = 0.0_dp
530 DO j = 1,
SIZE(col_indices)
531 DO i = 1,
SIZE(row_indices)
532 IF (row_atom(i) == col_atom(j))
THEN
533 m_pq_aa_local(i, j) = m_pq_local(i, j)
538 CALL timestop(handle)
540 END SUBROUTINE copy_m_pq_aa_blocks
547 SUBROUTINE compute_optimized_m_pq_inv_factors(eigenval, factors)
548 REAL(kind=
dp),
DIMENSION(:),
INTENT(IN) :: eigenval
549 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
550 INTENT(OUT) :: factors
552 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_optimized_M_pq_inv_factors'
554 INTEGER :: handle, i, n_dependent
555 REAL(kind=
dp) :: largest, threshold
557 CALL timeset(routinen, handle)
559 cpassert(
SIZE(eigenval) > 0)
561 largest = maxval(eigenval)
562 cpassert(largest > 0.0_dp)
563 threshold = optimized_m_eigenval_threshold*largest
564 ALLOCATE (factors(
SIZE(eigenval)))
567 DO i = 1,
SIZE(eigenval)
568 IF (eigenval(i) > 0.0_dp .AND. eigenval(i) >= threshold)
THEN
569 factors(i) = 1.0_dp/sqrt(eigenval(i))
571 n_dependent = n_dependent + 1
574 cpassert(n_dependent <
SIZE(eigenval))
576 CALL timestop(handle)
578 END SUBROUTINE compute_optimized_m_pq_inv_factors
586 PURE FUNCTION m_pq_index_atom(global_index, block_ends)
RESULT(atom_index)
587 INTEGER,
INTENT(IN) :: global_index
588 INTEGER,
DIMENSION(:),
INTENT(IN) :: block_ends
589 INTEGER :: atom_index
591 INTEGER :: high, low, middle
594 high =
SIZE(block_ends)
595 DO WHILE (low < high)
596 middle = (low + high)/2
597 IF (global_index <= block_ends(middle))
THEN
605 END FUNCTION m_pq_index_atom
616 SUBROUTINE compute_reference_m_pq_inv_factor(M_PQ, X_Pi, rank)
617 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: m_pq
618 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
620 INTEGER,
INTENT(OUT) :: rank
622 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_reference_M_PQ_inv_factor'
624 INTEGER :: column, handle, i, n
625 REAL(kind=
dp) :: largest
626 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eigenval
627 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: eigenvec
629 CALL timeset(routinen, handle)
632 cpassert(n > 0 .AND.
SIZE(m_pq, 2) == n)
633 ALLOCATE (eigenvec, source=0.5_dp*(m_pq + transpose(m_pq)))
634 ALLOCATE (eigenval(n))
635 CALL diamat_all(eigenvec, eigenval, dac=.true.)
636 largest = maxval(eigenval)
637 IF (largest <= 0.0_dp) cpabort(
"AUTO_RI metric has no positive non-null range")
638 IF (minval(eigenval) < -negative_eigenval_tolerance*largest)
THEN
639 cpabort(
"AUTO_RI metric has no positive non-null range")
641 rank = count(eigenval > reference_m_eigenval_threshold*largest)
642 IF (rank == 0) cpabort(
"AUTO_RI metric has no positive non-null range")
643 ALLOCATE (x_pi(n, rank))
646 IF (eigenval(i) <= reference_m_eigenval_threshold*largest) cycle
648 x_pi(:, column) = eigenvec(:, i)/sqrt(eigenval(i))
651 CALL timestop(handle)
653 END SUBROUTINE compute_reference_m_pq_inv_factor
666 SUBROUTINE solve_aa_eigenproblem(M_PQ, B_PQ, target_normalization, U_Pp_A, eigenval)
667 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: m_pq, b_pq
668 REAL(kind=
dp),
INTENT(IN) :: target_normalization
669 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
670 INTENT(OUT) :: u_pp_a
671 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:), &
672 INTENT(OUT) :: eigenval
674 CHARACTER(LEN=*),
PARAMETER :: routinen =
'solve_AA_eigenproblem'
676 INTEGER :: handle, i, j, m_pq_rank, n, nret
677 REAL(kind=
dp) :: largest_score, relative_fitting_defect
678 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:) :: eigenval_b, eigenval_m
679 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: b_ij, m_pp_check, u_ij, u_pp_a_rotated, &
682 CALL timeset(routinen, handle)
686 cpassert(
SIZE(m_pq, 2) == n)
687 cpassert(all(shape(b_pq) == [n, n]))
688 cpassert(target_normalization > 0.0_dp)
689 CALL compute_reference_m_pq_inv_factor(m_pq, x_pi, m_pq_rank)
691 ALLOCATE (b_ij(m_pq_rank, m_pq_rank))
692 b_ij(:, :) = matmul(transpose(x_pi), &
693 matmul(0.5_dp*(b_pq + transpose(b_pq)), x_pi))/target_normalization
694 ALLOCATE (u_ij, source=b_ij)
695 ALLOCATE (eigenval_b(m_pq_rank))
697 largest_score = maxval(eigenval_b)
698 IF (largest_score <= 0.0_dp)
THEN
699 cpabort(
"AUTO_RI conditioned atom-local eigensolver failed")
701 IF (minval(eigenval_b) < -negative_eigenval_tolerance*largest_score)
THEN
702 cpabort(
"AUTO_RI conditioned atom-local eigensolver failed")
704 nret = count(eigenval_b/largest_score >= relative_target_eigenval_threshold)
705 ALLOCATE (u_pp_a(n, nret), eigenval(m_pq_rank))
707 eigenval(i) = eigenval_b(m_pq_rank - i + 1)
710 j = m_pq_rank - i + 1
711 u_pp_a(:, i) = matmul(x_pi, u_ij(:, j))
714 relative_fitting_defect = 1.0_dp
716 j = m_pq_rank - i + 1
717 relative_fitting_defect = relative_fitting_defect - &
718 dot_product(u_ij(:, j), matmul(b_ij, u_ij(:, j)))
720 IF (abs(relative_fitting_defect) < 100.0_dp*epsilon(1.0_dp))
THEN
721 relative_fitting_defect = 0.0_dp
724 IF (relative_fitting_defect < -1.0e-8_dp .OR. &
725 relative_fitting_defect > 1.0_dp + 1.0e-8_dp)
THEN
726 cpabort(
"AUTO_RI conditioned atom-local eigensolver failed")
729 ALLOCATE (m_pp_check(nret, nret), eigenval_m(nret), u_pp_a_rotated(n, nret))
730 m_pp_check(:, :) = matmul(transpose(u_pp_a), &
731 matmul(0.5_dp*(m_pq + transpose(m_pq)), u_pp_a))
732 CALL diamat_all(m_pp_check, eigenval_m, dac=.true.)
733 IF (minval(eigenval_m) <= reference_m_eigenval_threshold)
THEN
734 cpabort(
"AUTO_RI conditioned atom-local eigensolver failed")
736 u_pp_a_rotated(:, :) = matmul(u_pp_a, m_pp_check)
738 u_pp_a_rotated(:, i) = u_pp_a_rotated(:, i)/sqrt(eigenval_m(i))
740 u_pp_a(:, :) = matmul(u_pp_a_rotated, transpose(m_pp_check))
741 m_pp_check(:, :) = matmul(transpose(u_pp_a), &
742 matmul(0.5_dp*(m_pq + transpose(m_pq)), u_pp_a))
744 m_pp_check(i, i) = m_pp_check(i, i) - 1.0_dp
746 IF (maxval(abs(m_pp_check)) >= 1.0e-7_dp)
THEN
747 cpabort(
"AUTO_RI conditioned atom-local eigensolver failed")
751 CALL timestop(handle)
753 END SUBROUTINE solve_aa_eigenproblem
765 SUBROUTINE solve_ab_eigenproblem(M_PQ, B_PQ, U_Pp_AA, U_Pp_AB, eigenval)
766 REAL(kind=
dp),
INTENT(IN) :: m_pq(:, :), b_pq(:, :), u_pp_aa(:, :)
767 REAL(kind=
dp),
ALLOCATABLE,
INTENT(OUT) :: u_pp_ab(:, :), eigenval(:)
769 CHARACTER(LEN=*),
PARAMETER :: routinen =
'solve_AB_eigenproblem'
771 INTEGER :: handle, i, k, n, nkeep, rank
772 REAL(kind=
dp) :: threshold
773 REAL(kind=
dp),
ALLOCATABLE :: b_ij(:, :), b_ij_residual(:, :), eigenval_residual(:), &
774 m_aa(:, :), p_ij(:, :), q_ia(:, :), u_aa(:, :), u_ia(:, :), x_pi(:, :)
776 CALL timeset(routinen, handle)
779 CALL compute_reference_m_pq_inv_factor(m_pq, x_pi, rank)
782 ALLOCATE (q_ia(rank,
SIZE(u_pp_aa, 2)))
783 q_ia(:, :) = matmul(transpose(x_pi), matmul(m_pq, u_pp_aa))
784 ALLOCATE (p_ij(rank, rank), source=0.0_dp)
788 IF (
SIZE(u_pp_aa, 2) > 0)
THEN
789 ALLOCATE (m_aa(
SIZE(u_pp_aa, 2),
SIZE(u_pp_aa, 2)))
790 m_aa(:, :) = matmul(transpose(q_ia), q_ia)
791 CALL compute_reference_m_pq_inv_factor(m_aa, u_aa, k)
792 ALLOCATE (u_ia(rank,
SIZE(u_aa, 2)))
793 u_ia(:, :) = matmul(q_ia, u_aa)
794 p_ij(:, :) = p_ij - matmul(u_ia, transpose(u_ia))
797 ALLOCATE (b_ij(rank, rank))
798 b_ij(:, :) = matmul(transpose(x_pi), matmul(b_pq, x_pi))
799 ALLOCATE (b_ij_residual(rank, rank))
800 b_ij_residual(:, :) = matmul(p_ij, matmul(b_ij, p_ij))
801 ALLOCATE (eigenval_residual(rank))
802 CALL diamat_all(b_ij_residual, eigenval_residual, dac=.true.)
803 threshold = max(ab_absolute_target_eigenval_threshold, &
804 relative_target_eigenval_threshold*maxval(eigenval_residual), &
805 100.0_dp*epsilon(1.0_dp)*maxval(abs(b_ij)))
806 nkeep = count(eigenval_residual > threshold)
807 ALLOCATE (u_pp_ab(n, nkeep), eigenval(nkeep))
810 IF (eigenval_residual(i) <= threshold) cycle
812 u_pp_ab(:, k) = matmul(x_pi, matmul(p_ij, b_ij_residual(:, i)))
813 eigenval(k) = eigenval_residual(i)
816 CALL timestop(handle)
818 END SUBROUTINE solve_ab_eigenproblem
827 SUBROUTINE select_ri_sizes(eigenval_by_block, RI_size_requested, RI_size_minimum, &
829 REAL(kind=
dp),
INTENT(IN) :: eigenval_by_block(:, :)
830 INTEGER,
INTENT(IN) :: ri_size_requested, ri_size_minimum
831 INTEGER,
INTENT(OUT) :: sizes_ri_selected(:)
833 CHARACTER(LEN=*),
PARAMETER :: routinen =
'select_RI_sizes'
835 INTEGER :: block, handle, i, n, nmode, remaining
836 INTEGER,
ALLOCATABLE :: indices(:)
837 REAL(kind=
dp),
ALLOCATABLE :: values(:)
839 CALL timeset(routinen, handle)
841 nmode =
SIZE(eigenval_by_block, 1)
842 n =
SIZE(eigenval_by_block)
843 cpassert(
SIZE(sizes_ri_selected) ==
SIZE(eigenval_by_block, 2))
844 cpassert(ri_size_minimum >= 0)
845 sizes_ri_selected(:) = 0
847 ALLOCATE (values(n), indices(n))
848 values(:) = -reshape(eigenval_by_block, [n])
849 DO block = 1,
SIZE(sizes_ri_selected)
850 sizes_ri_selected(block) = &
851 min(ri_size_minimum, count(eigenval_by_block(:, block) > 0.0_dp))
852 values((block - 1)*nmode + 1: &
853 (block - 1)*nmode + sizes_ri_selected(block)) = 0.0_dp
855 CALL sort(values, n, indices)
856 remaining = min(max(0, ri_size_requested - sum(sizes_ri_selected)), count(values < 0.0_dp))
858 block = (indices(i) - 1)/nmode + 1
859 sizes_ri_selected(block) = sizes_ri_selected(block) + 1
863 CALL timestop(handle)
865 END SUBROUTINE select_ri_sizes
875 SUBROUTINE compute_orbital_weights(eigenval_MO, homo, weights)
876 REAL(kind=
dp),
INTENT(IN) :: eigenval_mo(:)
877 INTEGER,
INTENT(IN) :: homo
878 REAL(kind=
dp),
INTENT(OUT) :: weights(:)
880 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_orbital_weights'
883 REAL(kind=
dp) :: gap, middle
885 CALL timeset(routinen, handle)
887 cpassert(
SIZE(weights) ==
SIZE(eigenval_mo))
888 IF (homo < 1 .OR. homo >=
SIZE(eigenval_mo))
THEN
889 cpabort(
"AUTO_RI orbital weights require occupied and empty states")
891 IF (.NOT. all(ieee_is_finite(eigenval_mo)))
THEN
892 cpabort(
"AUTO_RI orbital weights require finite eigenvalues")
894 gap = eigenval_mo(homo + 1) - eigenval_mo(homo)
895 IF (.NOT. ieee_is_finite(gap) .OR. gap <= 0.0_dp)
THEN
896 cpabort(
"AUTO_RI orbital weights require a finite positive gap")
898 middle = 0.5_dp*(eigenval_mo(homo) + eigenval_mo(homo + 1))
899 DO n = 1,
SIZE(eigenval_mo)
900 weights(n) = 1.0_dp/abs(eigenval_mo(n) - middle)
903 CALL timestop(handle)
905 END SUBROUTINE compute_orbital_weights
918 SUBROUTINE compute_b_pq_transition(Int_3c, C_mu_n, weights, homo, B_PQ)
919 REAL(kind=
dp),
CONTIGUOUS,
INTENT(IN) :: int_3c(:, :, :), c_mu_n(:, :), weights(:)
920 INTEGER,
INTENT(IN) :: homo
921 REAL(kind=
dp),
INTENT(OUT) :: b_pq(:, :)
923 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_B_PQ_transition'
925 INTEGER :: handle, n, nao, nri, nstates
926 REAL(kind=
dp),
ALLOCATABLE :: empty(:, :), occupied(:, :), scaled(:, :)
929 CALL timeset(routinen, handle)
932 nao =
SIZE(c_mu_n, 1)
933 nstates =
SIZE(c_mu_n, 2)
934 nri =
SIZE(int_3c, 3)
935 cpassert(
SIZE(int_3c, 1) == nao .AND.
SIZE(int_3c, 2) == nao)
936 cpassert(
SIZE(b_pq, 1) == nri .AND.
SIZE(b_pq, 2) == nri)
937 cpassert(
SIZE(weights) == nstates .AND. homo > 0 .AND. homo < nstates)
938 ALLOCATE (scaled(nao, nstates), occupied(nao, nao), empty(nao, nao))
940 scaled(:, n) = c_mu_n(:, n)*sqrt(weights(n))
942 CALL gemm_context%gemm( &
943 'N',
'T', nao, nao, homo, 1.0_dp, scaled, nao, scaled, nao, &
944 0.0_dp, occupied, nao)
945 CALL gemm_context%gemm(
'N',
'T', nao, nao, nstates - homo, 1.0_dp, &
946 scaled(:, homo + 1:), nao, scaled(:, homo + 1:), nao, &
948 CALL contract_b_pq(int_3c, occupied, empty, b_pq)
949 CALL gemm_context%destroy()
951 CALL timestop(handle)
953 END SUBROUTINE compute_b_pq_transition
967 SUBROUTINE compute_b_pq_exchange(Int_3c, C_mu_n, eigenval_MO, homo, occ_energy_window, B_PQ)
968 REAL(kind=
dp),
CONTIGUOUS,
INTENT(IN) :: int_3c(:, :, :), c_mu_n(:, :), &
970 INTEGER,
INTENT(IN) :: homo
971 REAL(kind=
dp),
INTENT(IN) :: occ_energy_window
972 REAL(kind=
dp),
INTENT(OUT) :: b_pq(:, :)
974 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_B_PQ_exchange'
976 INTEGER :: handle, n, nao, nstates
977 REAL(kind=
dp),
ALLOCATABLE :: frontier(:, :), occupied(:, :), &
981 CALL timeset(routinen, handle)
984 nstates =
SIZE(eigenval_mo)
985 IF (homo < 1 .OR. homo >= nstates)
THEN
986 cpabort(
"AUTO_RI exchange target requires occupied and empty states")
988 IF (.NOT. ieee_is_finite(occ_energy_window) .OR. &
989 .NOT. all(ieee_is_finite(eigenval_mo)))
THEN
990 cpabort(
"AUTO_RI exchange target requires finite input")
992 IF (occ_energy_window < 0.0_dp .OR. eigenval_mo(homo + 1) <= eigenval_mo(homo))
THEN
993 cpabort(
"AUTO_RI exchange target requires a valid frontier window")
995 nao =
SIZE(c_mu_n, 1)
996 cpassert(
SIZE(c_mu_n, 2) == nstates)
997 ALLOCATE (occupied(nao, nao), frontier(nao, nao), selected(nao, nstates), source=0.0_dp)
999 IF (eigenval_mo(n) < eigenval_mo(homo) - occ_energy_window .OR. &
1000 eigenval_mo(n) > eigenval_mo(homo + 1) + occ_energy_window) cycle
1001 selected(:, n) = c_mu_n(:, n)
1006 CALL gemm_context%gemm(
'N',
'T', nao, nao, homo, 1.0_dp, c_mu_n, nao, c_mu_n, nao, &
1007 0.0_dp, occupied, nao)
1008 CALL gemm_context%gemm(
'N',
'T', nao, nao, nstates, 1.0_dp, selected, nao, selected, nao, &
1009 0.0_dp, frontier, nao)
1010 CALL contract_b_pq(int_3c, occupied, frontier, b_pq)
1011 CALL gemm_context%destroy()
1013 CALL timestop(handle)
1015 END SUBROUTINE compute_b_pq_exchange
1027 SUBROUTINE contract_b_pq(Int_3c, left, right, B_PQ)
1028 REAL(kind=
dp),
CONTIGUOUS,
INTENT(IN) :: int_3c(:, :, :), left(:, :), right(:, :)
1029 REAL(kind=
dp),
INTENT(OUT) :: b_pq(:, :)
1031 CHARACTER(LEN=*),
PARAMETER :: routinen =
'contract_B_PQ'
1033 INTEGER :: b, handle, mu, naux, nu, p, q
1034 REAL(kind=
dp),
ALLOCATABLE :: weighted(:, :), work(:, :)
1037 CALL timeset(routinen, handle)
1040 naux =
SIZE(int_3c, 3)
1041 cpassert(
SIZE(int_3c, 2) == b)
1042 cpassert(
SIZE(left, 1) == b .AND.
SIZE(left, 2) == b)
1043 cpassert(
SIZE(right, 1) == b .AND.
SIZE(right, 2) == b)
1044 cpassert(
SIZE(b_pq, 1) == naux .AND.
SIZE(b_pq, 2) == naux)
1045 ALLOCATE (work(b, b), weighted(b, b))
1049 CALL gemm_context%gemm(
'N',
'N', b, b, b, 1.0_dp, left, b, int_3c(:, :, q), b, &
1051 CALL gemm_context%gemm(
'N',
'N', b, b, b, 1.0_dp, work, b, right, b, 0.0_dp, weighted, b)
1056 b_pq(p, q) = b_pq(p, q) + int_3c(mu, nu, p)*weighted(mu, nu)
1059 b_pq(q, p) = b_pq(p, q)
1062 CALL gemm_context%destroy()
1064 CALL timestop(handle)
1066 END SUBROUTINE contract_b_pq
1075 SUBROUTINE combine_transition_and_exchange_targets( &
1076 X_Pi, B_PQ_transition, B_PQ_exchange, target_norm)
1077 REAL(kind=
dp),
CONTIGUOUS,
INTENT(IN) :: x_pi(:, :)
1078 REAL(kind=
dp),
INTENT(INOUT) :: b_pq_transition(:, :)
1079 REAL(kind=
dp),
CONTIGUOUS,
INTENT(IN) :: b_pq_exchange(:, :)
1080 REAL(kind=
dp),
INTENT(OUT) :: target_norm
1082 CHARACTER(LEN=*),
PARAMETER :: routinen =
'combine_transition_and_exchange_targets'
1084 INTEGER :: handle, k
1085 REAL(kind=
dp) :: exchange_norm, transition_norm
1086 REAL(kind=
dp),
ALLOCATABLE :: work(:, :)
1088 CALL timeset(routinen, handle)
1090 ALLOCATE (work(
SIZE(x_pi, 1),
SIZE(x_pi, 2)))
1091 work(:, :) = matmul(b_pq_transition, x_pi)
1092 transition_norm = 0.0_dp
1093 DO k = 1,
SIZE(x_pi, 2)
1094 transition_norm = transition_norm + dot_product(x_pi(:, k), work(:, k))
1096 work(:, :) = matmul(b_pq_exchange, x_pi)
1097 exchange_norm = 0.0_dp
1098 DO k = 1,
SIZE(x_pi, 2)
1099 exchange_norm = exchange_norm + dot_product(x_pi(:, k), work(:, k))
1101 target_norm = 0.0_dp
1102 IF (.NOT. ieee_is_finite(transition_norm) .OR. &
1103 .NOT. ieee_is_finite(exchange_norm) .OR. &
1104 transition_norm < 0.0_dp .OR. exchange_norm < 0.0_dp)
THEN
1105 cpabort(
"AUTO_RI target normalization is invalid")
1108 IF (transition_norm > 0.0_dp)
THEN
1109 b_pq_transition(:, :) = b_pq_transition/transition_norm
1110 target_norm = target_norm + 1.0_dp
1112 b_pq_transition(:, :) = 0.0_dp
1114 IF (exchange_norm > 0.0_dp)
THEN
1115 b_pq_transition(:, :) = b_pq_transition + b_pq_exchange/exchange_norm
1116 target_norm = target_norm + 1.0_dp
1118 IF (target_norm <= 0.0_dp .OR. .NOT. all(ieee_is_finite(b_pq_transition)))
THEN
1119 cpabort(
"AUTO_RI target normalization is invalid")
1122 CALL timestop(handle)
1124 END SUBROUTINE combine_transition_and_exchange_targets
1141 SUBROUTINE compute_b_pq_aa(bs_env, iatom, root_rank, Int_3c, M_PQ, &
1144 INTEGER,
INTENT(IN) :: iatom, root_rank
1145 REAL(kind=
dp),
CONTIGUOUS,
INTENT(IN) :: int_3c(:, :, :), m_pq(:, :)
1146 REAL(kind=
dp),
ALLOCATABLE,
INTENT(OUT) :: b_pq(:, :)
1147 REAL(kind=
dp),
INTENT(OUT) :: target_norm
1149 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_B_PQ_AA'
1151 INTEGER :: column, first, handle, i, j, nao, nri, &
1152 nstates, rank, row, spin
1153 INTEGER,
POINTER :: cols(:), rows(:)
1154 REAL(kind=
dp),
ALLOCATABLE :: b_pq_exchange(:, :), b_pq_spin(:, :), &
1155 c_mu_n(:, :), weights(:), x_pi(:, :)
1157 CALL timeset(routinen, handle)
1158 NULLIFY (rows, cols)
1159 nao =
SIZE(int_3c, 1)
1160 nri =
SIZE(int_3c, 3)
1161 nstates = bs_env%n_mo_retained
1162 cpassert(
ALLOCATED(bs_env%eigenval_scf_Gamma))
1163 first = 1 + sum(bs_env%sizes_AO(:iatom - 1))
1164 ALLOCATE (b_pq(nri, nri), source=0.0_dp)
1165 ALLOCATE (c_mu_n(nao, nstates), weights(nstates), b_pq_spin(nri, nri))
1166 target_norm = 0.0_dp
1167 ALLOCATE (b_pq_exchange(nri, nri), source=0.0_dp)
1168 DO spin = 1, bs_env%n_spin
1169 CALL compute_orbital_weights(bs_env%eigenval_scf_Gamma(1:nstates, spin), &
1170 bs_env%n_occ(spin), weights)
1171 CALL cp_fm_get_info(bs_env%fm_mo_coeff_Gamma(spin), row_indices=rows, col_indices=cols)
1172 c_mu_n(:, :) = 0.0_dp
1173 DO i = 1,
SIZE(rows)
1174 row = rows(i) - first + 1
1175 IF (row < 1 .OR. row > nao) cycle
1176 DO j = 1,
SIZE(cols)
1178 IF (column > nstates) cycle
1179 c_mu_n(row, column) = bs_env%fm_mo_coeff_Gamma(spin)%local_data(i, j)
1182 CALL bs_env%para_env%sum(c_mu_n, root_rank)
1183 IF (bs_env%para_env%mepos /= root_rank) cycle
1184 CALL compute_b_pq_transition(int_3c, c_mu_n, weights, bs_env%n_occ(spin), b_pq_spin)
1185 b_pq(:, :) = b_pq + b_pq_spin
1186 CALL compute_b_pq_exchange(int_3c, c_mu_n, &
1187 bs_env%eigenval_scf_Gamma(1:nstates, spin), &
1188 bs_env%n_occ(spin), bs_env%auto_ri%occ_energy_window, b_pq_spin)
1189 b_pq_exchange(:, :) = b_pq_exchange + b_pq_spin
1191 IF (bs_env%para_env%mepos /= root_rank)
THEN
1192 CALL timestop(handle)
1195 CALL compute_reference_m_pq_inv_factor(m_pq, x_pi, rank)
1196 CALL combine_transition_and_exchange_targets(x_pi, b_pq, b_pq_exchange, target_norm)
1197 CALL timestop(handle)
1199 END SUBROUTINE compute_b_pq_aa
1207 SUBROUTINE normalize_ri_coefficients(U_Pp)
1208 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: u_pp
1210 CHARACTER(LEN=*),
PARAMETER :: routinen =
'normalize_RI_coefficients'
1212 INTEGER :: handle, j
1213 REAL(kind=
dp) :: column_norm
1215 CALL timeset(routinen, handle)
1217 DO j = 1,
SIZE(u_pp, 2)
1218 column_norm = norm2(u_pp(:, j))
1219 IF (column_norm <= tiny(1.0_dp))
THEN
1220 cpabort(
"AUTO_RI produced a numerically zero localized column")
1222 u_pp(:, j) = u_pp(:, j)/column_norm
1225 CALL timestop(handle)
1227 END SUBROUTINE normalize_ri_coefficients
1236 SUBROUTINE create_distributed_matrix(qs_env, matrix, nr, nc)
1239 INTEGER,
INTENT(IN) :: nr, nc
1241 CHARACTER(LEN=*),
PARAMETER :: routinen =
'create_distributed_matrix'
1248 CALL timeset(routinen, handle)
1250 NULLIFY (blacs, para, layout)
1251 CALL get_qs_env(qs_env, blacs_env=blacs, para_env=para)
1252 CALL cp_fm_struct_create(layout, context=blacs, nrow_global=nr, ncol_global=nc, para_env=para)
1256 CALL timestop(handle)
1258 END SUBROUTINE create_distributed_matrix
1271 SUBROUTINE compute_ab_optimized_ri_basis(qs_env, bs_env, U_Pp_A)
1274 REAL(kind=
dp),
DIMENSION(:, :, :),
INTENT(IN) :: u_pp_a
1276 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_AB_optimized_RI_basis'
1278 INTEGER :: ab_pair_count, center_index, current_atom, expected_ri_size, first_ab_pair, &
1279 handle, handle_pair_batches, iatom, jatom, k, last_ab_pair, nao_kind, nri_a, nri_ab_ref, &
1280 nri_b, ri_size_opt_aa, ri_size_opt_ab, ri_size_optimized, ri_size_ref, ri_size_requested, &
1281 root_rank, row, size_opt_ri_ab, size_u_pp_ab, size_u_pp_ab_storage, spin
1282 INTEGER,
ALLOCATABLE :: ab_atom_a(:), ab_atom_b(:), ab_size_opt_ri_to_a(:), block_next(:), &
1283 sizes_opt_ri_aa(:), sizes_opt_ri_ab(:), sizes_ref_ri(:), u_pp_ab_offset(:)
1284 REAL(kind=
dp),
ALLOCATABLE :: b_pq(:, :), c_mu_n_ab(:, :, :), c_mu_n_atom(:, :), &
1285 eigenval(:), eigenval_ab(:, :), m_pq(:, :), u_pp_aa(:, :), u_pp_ab(:, :), &
1291 CALL timeset(routinen, handle)
1295 ALLOCATE (sizes_ref_ri(bs_env%n_atom), sizes_opt_ri_aa(bs_env%n_atom))
1296 DO iatom = 1, bs_env%n_atom
1297 sizes_ref_ri(iatom) = get_ref_ri_size(bs_env, iatom)
1299 sizes_opt_ri_aa(:) = bs_env%auto_ri%sizes_opt_RI
1300 ri_size_ref = sum(sizes_ref_ri)
1301 ri_size_opt_aa = sum(sizes_opt_ri_aa)
1304 DO iatom = 1, bs_env%n_atom - 1
1305 DO jatom = iatom + 1, bs_env%n_atom
1306 IF (norm2(bs_env%ri_rs%particle_set(iatom)%r - bs_env%ri_rs%particle_set(jatom)%r) <= &
1307 bs_env%auto_ri%neighbor_radius)
THEN
1308 ab_pair_count = ab_pair_count + 1
1312 ALLOCATE (ab_atom_a(ab_pair_count), ab_atom_b(ab_pair_count), &
1313 ab_size_opt_ri_to_a(ab_pair_count), sizes_opt_ri_ab(ab_pair_count), &
1314 u_pp_ab_offset(ab_pair_count))
1315 ab_size_opt_ri_to_a = 0
1317 ALLOCATE (eigenval_ab(2*maxval(sizes_ref_ri), ab_pair_count), source=0.0_dp)
1319 CALL gw_3c_ctx_create(ctx, qs_env, bs_env%ri_metric, bs_env%basis_set_AO, &
1320 bs_env%basis_set_AO, bs_env%basis_set_RI)
1323 DO iatom = 1, bs_env%n_atom - 1
1324 DO jatom = iatom + 1, bs_env%n_atom
1325 IF (norm2(bs_env%ri_rs%particle_set(iatom)%r - bs_env%ri_rs%particle_set(jatom)%r) > &
1326 bs_env%auto_ri%neighbor_radius) cycle
1328 ab_atom_a(k) = iatom
1329 ab_atom_b(k) = jatom
1332 size_u_pp_ab_storage = 0
1333 DO k = 1, ab_pair_count
1334 root_rank =
modulo(k - 1, para%num_pe)
1335 IF (para%mepos /= root_rank) cycle
1336 nri_ab_ref = sizes_ref_ri(ab_atom_a(k)) + sizes_ref_ri(ab_atom_b(k))
1337 u_pp_ab_offset(k) = size_u_pp_ab_storage + 1
1338 size_u_pp_ab_storage = size_u_pp_ab_storage + nri_ab_ref*nri_ab_ref
1340 ALLOCATE (u_pp_ab_packed(size_u_pp_ab_storage))
1341 CALL timeset(routinen//
'_pair_batches', handle_pair_batches)
1342 DO first_ab_pair = 1, ab_pair_count, para%num_pe
1343 last_ab_pair = min(ab_pair_count, first_ab_pair + para%num_pe - 1)
1345 DO k = first_ab_pair, last_ab_pair
1346 root_rank = k - first_ab_pair
1347 iatom = ab_atom_a(k)
1348 jatom = ab_atom_b(k)
1349 IF (para%mepos == root_rank)
THEN
1350 ALLOCATE (c_mu_n_ab( &
1351 bs_env%sizes_AO(iatom) + bs_env%sizes_AO(jatom), &
1352 bs_env%n_mo_retained, bs_env%n_spin))
1354 DO spin = 1, bs_env%n_spin
1356 DO center_index = 1, 2
1357 current_atom = iatom
1358 IF (center_index == 2) current_atom = jatom
1359 nao_kind = bs_env%sizes_AO(current_atom)
1360 ALLOCATE (c_mu_n_atom(nao_kind, bs_env%n_mo_retained))
1362 start_row=1 + sum(bs_env%sizes_AO(:current_atom - 1)))
1363 IF (para%mepos == root_rank)
THEN
1364 c_mu_n_ab(row + 1:row + nao_kind, :, spin) = c_mu_n_atom
1366 DEALLOCATE (c_mu_n_atom)
1367 row = row + nao_kind
1371 k = first_ab_pair + para%mepos
1372 IF (k <= last_ab_pair)
THEN
1373 iatom = ab_atom_a(k)
1374 jatom = ab_atom_b(k)
1375 nri_a = sizes_ref_ri(iatom)
1376 nri_b = sizes_ref_ri(jatom)
1377 nri_ab_ref = nri_a + nri_b
1379 CALL compute_b_pq_ab(bs_env, ctx, ws, iatom, jatom, c_mu_n_ab, m_pq, b_pq)
1380 ALLOCATE (u_pp_aa(nri_ab_ref, sizes_opt_ri_aa(iatom) + sizes_opt_ri_aa(jatom)), &
1382 u_pp_aa(1:nri_a, 1:sizes_opt_ri_aa(iatom)) = &
1383 u_pp_a(1:nri_a, 1:sizes_opt_ri_aa(iatom), iatom)
1384 u_pp_aa(nri_a + 1:, sizes_opt_ri_aa(iatom) + 1:) = &
1385 u_pp_a(1:nri_b, 1:sizes_opt_ri_aa(jatom), jatom)
1387 CALL solve_ab_eigenproblem(m_pq, b_pq, u_pp_aa, u_pp_ab, eigenval)
1388 eigenval_ab(1:
SIZE(eigenval), k) = eigenval
1389 DEALLOCATE (eigenval)
1390 u_pp_ab_packed(u_pp_ab_offset(k):u_pp_ab_offset(k) +
SIZE(u_pp_ab) - 1) = &
1391 reshape(u_pp_ab, [
SIZE(u_pp_ab)])
1392 DEALLOCATE (u_pp_ab)
1393 DEALLOCATE (u_pp_aa, b_pq, m_pq, c_mu_n_ab)
1396 CALL timestop(handle_pair_batches)
1400 ri_size_requested = nint(min(bs_env%auto_ri%ri_ao_ratio, &
1401 REAL(ri_size_ref,
dp)/
REAL(SUM(bs_env%sizes_AO),
dp))* &
1402 REAL(SUM(bs_env%sizes_AO),
dp))
1403 ri_size_requested = max(ri_size_requested, bs_env%n_atom)
1405 CALL para%sum(eigenval_ab)
1406 CALL select_ri_sizes(eigenval_ab, ri_size_requested - sum(sizes_opt_ri_aa), 0, &
1408 ri_size_opt_ab = sum(sizes_opt_ri_ab)
1409 bs_env%auto_ri%sizes_opt_RI(:) = sizes_opt_ri_aa
1410 DO k = 1, ab_pair_count
1411 iatom = ab_atom_a(k)
1412 jatom = ab_atom_b(k)
1413 size_opt_ri_ab = sizes_opt_ri_ab(k)
1414 ab_size_opt_ri_to_a(k) = balance_ab_columns(bs_env%auto_ri%sizes_opt_RI(iatom), &
1415 bs_env%auto_ri%sizes_opt_RI(jatom), &
1417 bs_env%auto_ri%sizes_opt_RI(iatom) = &
1418 bs_env%auto_ri%sizes_opt_RI(iatom) + ab_size_opt_ri_to_a(k)
1419 bs_env%auto_ri%sizes_opt_RI(jatom) = &
1420 bs_env%auto_ri%sizes_opt_RI(jatom) + size_opt_ri_ab - ab_size_opt_ri_to_a(k)
1423 ri_size_optimized = sum(bs_env%auto_ri%sizes_opt_RI)
1424 expected_ri_size = ri_size_opt_aa + ri_size_opt_ab
1425 cpassert(ri_size_optimized == expected_ri_size)
1426 cpassert(all(bs_env%auto_ri%sizes_opt_RI > 0))
1427 IF (ri_size_optimized > ri_size_ref)
THEN
1428 cpabort(
"AUTO_RI request exceeds independent reference RI directions")
1431 DO iatom = 1, bs_env%n_atom
1432 size_u_pp_ab = size_u_pp_ab + sizes_ref_ri(iatom)*sizes_opt_ri_aa(iatom)
1434 DO k = 1, ab_pair_count
1435 size_u_pp_ab = size_u_pp_ab + &
1436 (sizes_ref_ri(ab_atom_a(k)) + &
1437 sizes_ref_ri(ab_atom_b(k)))*sizes_opt_ri_ab(k)
1439 ALLOCATE (bs_env%auto_ri%AB_atom_A(bs_env%n_atom + ab_pair_count), source=0)
1440 ALLOCATE (bs_env%auto_ri%AB_atom_B(bs_env%n_atom + ab_pair_count), source=0)
1441 ALLOCATE (bs_env%auto_ri%AB_first_p_A(bs_env%n_atom + ab_pair_count), source=0)
1442 ALLOCATE (bs_env%auto_ri%AB_first_p_B(bs_env%n_atom + ab_pair_count), source=0)
1443 ALLOCATE (bs_env%auto_ri%AB_size_opt_RI_to_A(bs_env%n_atom + ab_pair_count), source=0)
1444 ALLOCATE (bs_env%auto_ri%AB_size_ref_RI(bs_env%n_atom + ab_pair_count), source=0)
1445 ALLOCATE (bs_env%auto_ri%AB_size_opt_RI(bs_env%n_atom + ab_pair_count), source=0)
1446 ALLOCATE (bs_env%auto_ri%U_Pp_AB_offset(bs_env%n_atom + ab_pair_count), source=0)
1447 ALLOCATE (bs_env%auto_ri%U_Pp_AB(size_u_pp_ab), source=0.0_dp)
1448 bs_env%auto_ri%AB_block_count = 0
1450 ALLOCATE (block_next(bs_env%n_atom))
1452 DO iatom = 2, bs_env%n_atom
1453 block_next(iatom) = block_next(iatom - 1) + bs_env%auto_ri%sizes_opt_RI(iatom - 1)
1455 DO iatom = 1, bs_env%n_atom
1456 IF (sizes_opt_ri_aa(iatom) > 0) bs_env%auto_ri%AB_block_count = &
1457 bs_env%auto_ri%AB_block_count + 1
1458 CALL store_aa_columns(bs_env, iatom, &
1459 u_pp_a(1:sizes_ref_ri(iatom), 1:sizes_opt_ri_aa(iatom), iatom), &
1463 DO k = 1, ab_pair_count
1464 iatom = ab_atom_a(k)
1465 jatom = ab_atom_b(k)
1466 size_opt_ri_ab = sizes_opt_ri_ab(k)
1467 IF (size_opt_ri_ab == 0) cycle
1468 root_rank =
modulo(k - 1, para%num_pe)
1469 nri_ab_ref = sizes_ref_ri(iatom) + sizes_ref_ri(jatom)
1470 ALLOCATE (u_pp_ab(nri_ab_ref, size_opt_ri_ab))
1471 IF (para%mepos == root_rank)
THEN
1472 u_pp_ab(:, :) = reshape( &
1473 u_pp_ab_packed(u_pp_ab_offset(k): &
1474 u_pp_ab_offset(k) + &
1475 nri_ab_ref*size_opt_ri_ab - 1), &
1476 [nri_ab_ref, size_opt_ri_ab])
1478 CALL para%bcast(u_pp_ab, root_rank)
1479 bs_env%auto_ri%AB_block_count = bs_env%auto_ri%AB_block_count + 1
1481 CALL store_ab_columns(bs_env, u_pp_ab, iatom, jatom, ab_size_opt_ri_to_a(k), block_next)
1482 DEALLOCATE (u_pp_ab)
1485 DO iatom = 1, bs_env%n_atom
1486 expected_ri_size = 1 + sum(bs_env%auto_ri%sizes_opt_RI(:iatom))
1487 cpassert(block_next(iatom) == expected_ri_size)
1489 DEALLOCATE (block_next, ab_atom_a, ab_atom_b, ab_size_opt_ri_to_a, &
1490 u_pp_ab_offset, u_pp_ab_packed)
1492 CALL timestop(handle)
1494 END SUBROUTINE compute_ab_optimized_ri_basis
1503 PURE INTEGER FUNCTION balance_ab_columns(load_a, load_b, RI_size_opt_AB)
RESULT(RI_size_to_a)
1504 INTEGER,
INTENT(IN) :: load_a, load_b, ri_size_opt_ab
1506 ri_size_to_a = (load_b + ri_size_opt_ab - load_a + 1)/2
1507 ri_size_to_a = max(0, min(ri_size_opt_ab, ri_size_to_a))
1509 END FUNCTION balance_ab_columns
1518 SUBROUTINE store_aa_columns(bs_env, atom, U_Pp_A, block_next)
1520 INTEGER,
INTENT(IN) ::
atom
1521 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: u_pp_a
1522 INTEGER,
DIMENSION(:),
INTENT(INOUT) :: block_next
1524 CHARACTER(LEN=*),
PARAMETER :: routinen =
'store_AA_columns'
1526 INTEGER :: ab_block, first, handle, ri_size_opt_aa
1527 REAL(kind=
dp),
ALLOCATABLE :: u_pp_a_normalized(:, :)
1529 CALL timeset(routinen, handle)
1531 first = block_next(
atom)
1532 ab_block = bs_env%auto_ri%AB_block_count
1533 ri_size_opt_aa =
SIZE(u_pp_a, 2)
1534 ALLOCATE (u_pp_a_normalized(
SIZE(u_pp_a, 1), ri_size_opt_aa))
1535 IF (ri_size_opt_aa > 0)
THEN
1536 u_pp_a_normalized(:, :) = u_pp_a
1537 CALL normalize_ri_coefficients(u_pp_a_normalized)
1538 bs_env%auto_ri%AB_atom_A(ab_block) =
atom
1539 bs_env%auto_ri%AB_atom_B(ab_block) =
atom
1540 bs_env%auto_ri%AB_first_p_A(ab_block) = &
1541 first - sum(bs_env%auto_ri%sizes_opt_RI(:
atom - 1))
1542 bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block) = ri_size_opt_aa
1543 CALL store_u_pp_ab(bs_env%auto_ri, ab_block, u_pp_a_normalized)
1545 DEALLOCATE (u_pp_a_normalized)
1546 block_next(
atom) = first + ri_size_opt_aa
1548 CALL timestop(handle)
1550 END SUBROUTINE store_aa_columns
1561 SUBROUTINE store_ab_columns(bs_env, U_Pp_AB, atom_A, atom_B, RI_size_to_a, block_next)
1563 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
1564 INTENT(INOUT) :: u_pp_ab
1565 INTEGER,
INTENT(IN) :: atom_a, atom_b, ri_size_to_a
1566 INTEGER,
DIMENSION(:),
INTENT(INOUT) :: block_next
1568 CHARACTER(LEN=*),
PARAMETER :: routinen =
'store_AB_columns'
1570 INTEGER :: ab_block, first_a, first_b, handle, &
1573 CALL timeset(routinen, handle)
1575 ri_size_opt_ab =
SIZE(u_pp_ab, 2)
1576 ab_block = bs_env%auto_ri%AB_block_count
1577 first_a = block_next(atom_a)
1578 first_b = block_next(atom_b)
1579 CALL normalize_ri_coefficients(u_pp_ab)
1581 bs_env%auto_ri%AB_atom_A(ab_block) = atom_a
1582 bs_env%auto_ri%AB_atom_B(ab_block) = atom_b
1583 bs_env%auto_ri%AB_first_p_A(ab_block) = first_a - sum(bs_env%auto_ri%sizes_opt_RI(:atom_a - 1))
1584 bs_env%auto_ri%AB_first_p_B(ab_block) = first_b - sum(bs_env%auto_ri%sizes_opt_RI(:atom_b - 1))
1585 bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block) = ri_size_to_a
1586 CALL store_u_pp_ab(bs_env%auto_ri, ab_block, u_pp_ab)
1587 block_next(atom_a) = first_a + ri_size_to_a
1588 block_next(atom_b) = first_b + ri_size_opt_ab - ri_size_to_a
1590 CALL timestop(handle)
1592 END SUBROUTINE store_ab_columns
1600 SUBROUTINE store_u_pp_ab(auto_ri, AB_block, U_Pp)
1602 INTEGER,
INTENT(IN) :: ab_block
1603 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(IN) :: u_pp
1605 INTEGER :: first, last
1608 IF (ab_block > 1)
THEN
1609 first = auto_ri%U_Pp_AB_offset(ab_block - 1) + &
1610 auto_ri%AB_size_ref_RI(ab_block - 1)* &
1611 auto_ri%AB_size_opt_RI(ab_block - 1)
1613 last = first +
SIZE(u_pp) - 1
1614 cpassert(last <=
SIZE(auto_ri%U_Pp_AB))
1615 auto_ri%U_Pp_AB_offset(ab_block) = first
1616 auto_ri%AB_size_ref_RI(ab_block) =
SIZE(u_pp, 1)
1617 auto_ri%AB_size_opt_RI(ab_block) =
SIZE(u_pp, 2)
1618 auto_ri%U_Pp_AB(first:last) = reshape(u_pp, [
SIZE(u_pp)])
1620 END SUBROUTINE store_u_pp_ab
1637 SUBROUTINE compute_b_pq_ab(bs_env, ctx, ws, iatom, jatom, C_mu_n_AB, M_PQ, B_PQ)
1641 INTEGER,
INTENT(IN) :: iatom, jatom
1642 REAL(kind=
dp),
INTENT(IN) :: c_mu_n_ab(:, :, :)
1643 REAL(kind=
dp),
ALLOCATABLE,
INTENT(OUT) :: m_pq(:, :), b_pq(:, :)
1645 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_B_PQ_AB'
1647 INTEGER :: atoms(2), handle, homo, i, j, k, kind_a, kind_b, nao_ab, nri_ab_ref, &
1648 offset_ao(2), offset_ref_ri(2), rank, sizes_ao(2), sizes_ref_ri(2), spin
1650 REAL(kind=
dp) :: norm_exchange, norm_transition
1651 REAL(kind=
dp),
ALLOCATABLE :: b_pi(:, :), b_pq_exchange_ab(:, :), b_pq_exchange_full(:, :), &
1652 b_pq_spin(:, :), b_pq_transition_ab(:, :), b_pq_transition_full(:, :), &
1653 int_3c_ab(:, :, :), int_3c_all(:, :, :), m_pq_block(:, :), weights(:), x_pi(:, :)
1655 CALL timeset(routinen, handle)
1659 sizes_ao = bs_env%sizes_AO(atoms)
1661 sizes_ref_ri(i) = get_ref_ri_size(bs_env, atoms(i))
1664 offset_ao(2) = sizes_ao(1)
1665 offset_ref_ri(1) = 0
1666 offset_ref_ri(2) = sizes_ref_ri(1)
1667 nao_ab = sum(sizes_ao)
1668 nri_ab_ref = sum(sizes_ref_ri)
1669 ALLOCATE (b_pq(nri_ab_ref, nri_ab_ref), &
1670 m_pq(nri_ab_ref, nri_ab_ref), source=0.0_dp)
1671 ALLOCATE (int_3c_all(nao_ab, nao_ab, nri_ab_ref), source=0.0_dp)
1674 CALL compute_m_pq_ab( &
1675 bs_env, atoms(i), atoms(j), m_pq_block, bs_env%ri_metric)
1676 m_pq(offset_ref_ri(i) + 1:offset_ref_ri(i) + sizes_ref_ri(i), &
1677 offset_ref_ri(j) + 1:offset_ref_ri(j) + sizes_ref_ri(j)) = m_pq_block
1678 DEALLOCATE (m_pq_block)
1681 int_3c_all, ctx, ws, atom_j=atoms(j), atom_k=atoms(k), &
1682 atom_i=atoms(i), j_offset=offset_ao(j), k_offset=offset_ao(k), &
1683 i_offset=offset_ref_ri(i), screened=screened)
1687 kind_a = bs_env%ri_rs%particle_set(iatom)%atomic_kind%kind_number
1688 kind_b = bs_env%ri_rs%particle_set(jatom)%atomic_kind%kind_number
1689 CALL add_ri_metric_regularization(bs_env%basis_set_RI(kind_a)%gto_basis_set, &
1690 bs_env%regularization_RI, m_pq)
1691 CALL add_ri_metric_regularization(bs_env%basis_set_RI(kind_b)%gto_basis_set, &
1692 bs_env%regularization_RI, m_pq, &
1693 offset=sizes_ref_ri(1))
1694 ALLOCATE (int_3c_ab, source=int_3c_all)
1695 int_3c_ab(1:sizes_ao(1), 1:sizes_ao(1), :) = 0.0_dp
1696 int_3c_ab(sizes_ao(1) + 1:, sizes_ao(1) + 1:, :) = 0.0_dp
1697 ALLOCATE (weights(bs_env%n_mo_retained), b_pq_spin(nri_ab_ref, nri_ab_ref))
1698 ALLOCATE (b_pq_transition_ab(nri_ab_ref, nri_ab_ref), &
1699 b_pq_exchange_ab(nri_ab_ref, nri_ab_ref), &
1700 b_pq_transition_full(nri_ab_ref, nri_ab_ref), &
1701 b_pq_exchange_full(nri_ab_ref, nri_ab_ref), &
1703 DO spin = 1, bs_env%n_spin
1704 homo = bs_env%n_occ(spin)
1705 CALL compute_orbital_weights( &
1706 eigenval_mo=bs_env%eigenval_scf_Gamma(1:bs_env%n_mo_retained, spin), &
1707 homo=homo, weights=weights)
1708 CALL compute_b_pq_transition(int_3c_all, c_mu_n_ab(:, :, spin), weights, homo, b_pq_spin)
1709 b_pq_transition_full(:, :) = b_pq_transition_full + b_pq_spin
1710 CALL compute_b_pq_transition(int_3c_ab, c_mu_n_ab(:, :, spin), weights, homo, b_pq_spin)
1711 b_pq_transition_ab(:, :) = b_pq_transition_ab + b_pq_spin
1712 CALL compute_b_pq_exchange(int_3c_all, c_mu_n_ab(:, :, spin), &
1713 bs_env%eigenval_scf_Gamma(1:bs_env%n_mo_retained, spin), &
1714 homo, bs_env%auto_ri%occ_energy_window, b_pq_spin)
1715 b_pq_exchange_full(:, :) = b_pq_exchange_full + b_pq_spin
1716 CALL compute_b_pq_exchange(int_3c_ab, c_mu_n_ab(:, :, spin), &
1717 bs_env%eigenval_scf_Gamma(1:bs_env%n_mo_retained, spin), &
1718 homo, bs_env%auto_ri%occ_energy_window, b_pq_spin)
1719 b_pq_exchange_ab(:, :) = b_pq_exchange_ab + b_pq_spin
1721 CALL compute_reference_m_pq_inv_factor(m_pq, x_pi, rank)
1722 DEALLOCATE (b_pq_spin)
1723 ALLOCATE (b_pi(nri_ab_ref, rank))
1724 b_pi(:, :) = matmul(b_pq_transition_full, x_pi)
1725 norm_transition = sum(x_pi*b_pi)
1726 b_pi(:, :) = matmul(b_pq_exchange_full, x_pi)
1727 norm_exchange = sum(x_pi*b_pi)
1729 IF (norm_transition > 0.0_dp)
THEN
1730 b_pq(:, :) = b_pq + 0.5_dp*b_pq_transition_ab/norm_transition
1732 IF (norm_exchange > 0.0_dp)
THEN
1733 b_pq(:, :) = b_pq + 0.5_dp*b_pq_exchange_ab/norm_exchange
1736 CALL timestop(handle)
1738 END SUBROUTINE compute_b_pq_ab
1745 SUBROUTINE build_ab_block_lists(bs_env, lists)
1747 TYPE(ab_block_list_type),
ALLOCATABLE,
INTENT(OUT) :: lists(:)
1749 CHARACTER(LEN=*),
PARAMETER :: routinen =
'build_AB_block_lists'
1751 INTEGER :: ab_block, atom_a, atom_b, handle, &
1752 position, ri_size_to_a, size_opt_ri_ab
1753 INTEGER,
ALLOCATABLE :: n_ab_blocks_by_atom(:)
1755 CALL timeset(routinen, handle)
1757 ALLOCATE (lists(bs_env%n_atom))
1758 ALLOCATE (n_ab_blocks_by_atom(bs_env%n_atom), source=0)
1759 DO ab_block = 1, bs_env%auto_ri%AB_block_count
1760 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1761 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1762 size_opt_ri_ab = bs_env%auto_ri%AB_size_opt_RI(ab_block)
1763 ri_size_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
1764 IF (ri_size_to_a > 0) n_ab_blocks_by_atom(atom_a) = n_ab_blocks_by_atom(atom_a) + 1
1765 IF (atom_b /= atom_a .AND. ri_size_to_a < size_opt_ri_ab)
THEN
1766 n_ab_blocks_by_atom(atom_b) = n_ab_blocks_by_atom(atom_b) + 1
1770 DO atom_a = 1, bs_env%n_atom
1771 ALLOCATE (lists(atom_a)%block(n_ab_blocks_by_atom(atom_a)))
1772 ALLOCATE (lists(atom_a)%first_p_AB(n_ab_blocks_by_atom(atom_a)))
1773 ALLOCATE (lists(atom_a)%first_p_atom(n_ab_blocks_by_atom(atom_a)))
1774 ALLOCATE (lists(atom_a)%size_opt_RI(n_ab_blocks_by_atom(atom_a)))
1776 n_ab_blocks_by_atom = 0
1777 DO ab_block = 1, bs_env%auto_ri%AB_block_count
1778 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1779 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1780 size_opt_ri_ab = bs_env%auto_ri%AB_size_opt_RI(ab_block)
1781 ri_size_to_a = bs_env%auto_ri%AB_size_opt_RI_to_A(ab_block)
1782 IF (ri_size_to_a > 0)
THEN
1783 position = n_ab_blocks_by_atom(atom_a) + 1
1784 n_ab_blocks_by_atom(atom_a) = position
1785 lists(atom_a)%block(position) = ab_block
1786 lists(atom_a)%first_p_AB(position) = 1
1787 lists(atom_a)%first_p_atom(position) = bs_env%auto_ri%AB_first_p_A(ab_block)
1788 lists(atom_a)%size_opt_RI(position) = ri_size_to_a
1790 IF (atom_b /= atom_a .AND. ri_size_to_a < size_opt_ri_ab)
THEN
1791 position = n_ab_blocks_by_atom(atom_b) + 1
1792 n_ab_blocks_by_atom(atom_b) = position
1793 lists(atom_b)%block(position) = ab_block
1794 lists(atom_b)%first_p_AB(position) = ri_size_to_a + 1
1795 lists(atom_b)%first_p_atom(position) = &
1796 bs_env%auto_ri%AB_first_p_B(ab_block)
1797 lists(atom_b)%size_opt_RI(position) = size_opt_ri_ab - ri_size_to_a
1800 DO atom_a = 1, bs_env%n_atom
1801 IF (sum(lists(atom_a)%size_opt_RI) /= bs_env%auto_ri%sizes_opt_RI(atom_a))
THEN
1802 cpabort(
"AUTO_RI AB-block columns do not fill the optimized atom block")
1805 DEALLOCATE (n_ab_blocks_by_atom)
1807 CALL timestop(handle)
1809 END SUBROUTINE build_ab_block_lists
1818 PURE INTEGER FUNCTION find_atom_position(atom, atoms, count)
RESULT(position)
1819 INTEGER,
INTENT(IN) ::
atom
1820 INTEGER,
DIMENSION(:),
INTENT(IN) :: atoms
1821 INTEGER,
INTENT(IN) :: count
1827 IF (atoms(i) ==
atom)
THEN
1833 END FUNCTION find_atom_position
1842 SUBROUTINE build_optimized_atom_u(bs_env, atom, list, atom_U)
1844 INTEGER,
INTENT(IN) ::
atom
1845 TYPE(ab_block_list_type),
INTENT(IN) ::
list
1846 TYPE(optimized_atom_u_type),
INTENT(OUT) :: atom_u
1848 CHARACTER(LEN=*),
PARAMETER :: routinen =
'build_optimized_atom_U'
1850 INTEGER :: ab_block, atom_a, atom_b, first, first_p_ab, first_p_atom, first_row, handle, i, &
1851 last, nri_ref_a, nri_ref_block, nsupport, position, size_opt_ri_ab
1852 INTEGER,
ALLOCATABLE :: support_atoms(:)
1853 REAL(kind=
dp),
ALLOCATABLE :: u_pp_ab(:, :)
1855 CALL timeset(routinen, handle)
1857 ALLOCATE (support_atoms(2*
SIZE(
list%block)))
1859 DO i = 1,
SIZE(
list%block)
1860 ab_block =
list%block(i)
1861 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1862 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1863 position = find_atom_position(atom_a, support_atoms, nsupport)
1864 IF (position == 0)
THEN
1865 nsupport = nsupport + 1
1866 support_atoms(nsupport) = atom_a
1868 IF (atom_b /= atom_a)
THEN
1869 position = find_atom_position(atom_b, support_atoms, nsupport)
1870 IF (position == 0)
THEN
1871 nsupport = nsupport + 1
1872 support_atoms(nsupport) = atom_b
1876 cpassert(nsupport > 0)
1877 ALLOCATE (atom_u%ref_atom(nsupport), atom_u%first_P(nsupport))
1878 atom_u%ref_atom(:) = support_atoms(:nsupport)
1881 atom_u%first_P(i) = first_row
1882 first_row = first_row + get_ref_ri_size(bs_env, atom_u%ref_atom(i))
1884 ALLOCATE (atom_u%U_Pp(first_row - 1, bs_env%auto_ri%sizes_opt_RI(
atom)), &
1887 DO i = 1,
SIZE(
list%block)
1888 ab_block =
list%block(i)
1889 atom_a = bs_env%auto_ri%AB_atom_A(ab_block)
1890 atom_b = bs_env%auto_ri%AB_atom_B(ab_block)
1891 nri_ref_block = bs_env%auto_ri%AB_size_ref_RI(ab_block)
1892 size_opt_ri_ab = bs_env%auto_ri%AB_size_opt_RI(ab_block)
1893 first = bs_env%auto_ri%U_Pp_AB_offset(ab_block)
1894 last = first + nri_ref_block*size_opt_ri_ab - 1
1895 ALLOCATE (u_pp_ab(nri_ref_block, size_opt_ri_ab))
1896 u_pp_ab(:, :) = reshape(bs_env%auto_ri%U_Pp_AB(first:last), &
1897 [nri_ref_block, size_opt_ri_ab])
1898 first_p_ab =
list%first_p_AB(i)
1899 first_p_atom =
list%first_p_atom(i)
1900 size_opt_ri_ab =
list%size_opt_RI(i)
1901 IF (first_p_ab < 1 .OR. &
1902 first_p_ab + size_opt_ri_ab - 1 >
SIZE(u_pp_ab, 2))
THEN
1903 cpabort(
"AUTO_RI AB-block column range is invalid")
1905 IF (first_p_atom < 1 .OR. &
1906 first_p_atom + size_opt_ri_ab - 1 > bs_env%auto_ri%sizes_opt_RI(
atom))
THEN
1907 cpabort(
"AUTO_RI optimized atom-block column range is invalid")
1910 nri_ref_a = get_ref_ri_size(bs_env, atom_a)
1911 position = find_atom_position(atom_a, atom_u%ref_atom, nsupport)
1912 cpassert(position > 0)
1913 first_row = atom_u%first_P(position)
1914 atom_u%U_Pp(first_row:first_row + nri_ref_a - 1, &
1915 first_p_atom:first_p_atom + size_opt_ri_ab - 1) = &
1916 u_pp_ab(1:nri_ref_a, first_p_ab:first_p_ab + size_opt_ri_ab - 1)
1917 IF (atom_b /= atom_a)
THEN
1918 position = find_atom_position(atom_b, atom_u%ref_atom, nsupport)
1919 cpassert(position > 0)
1920 first_row = atom_u%first_P(position)
1921 atom_u%U_Pp(first_row:first_row + get_ref_ri_size(bs_env, atom_b) - 1, &
1922 first_p_atom:first_p_atom + size_opt_ri_ab - 1) = &
1923 u_pp_ab(nri_ref_a + 1:, first_p_ab:first_p_ab + size_opt_ri_ab - 1)
1925 DEALLOCATE (u_pp_ab)
1927 DEALLOCATE (support_atoms)
1929 CALL timestop(handle)
1931 END SUBROUTINE build_optimized_atom_u
1939 SUBROUTINE regularize_m_pq_block(bs_env, atom, M_PQ)
1941 INTEGER,
INTENT(IN) ::
atom
1942 REAL(kind=
dp),
DIMENSION(:, :),
INTENT(INOUT) :: m_pq
1944 CHARACTER(LEN=*),
PARAMETER :: routinen =
'regularize_M_PQ_block'
1946 INTEGER :: handle, i, iset, kind, nset
1947 INTEGER,
DIMENSION(:),
POINTER :: npgf, nsgf_set
1948 INTEGER,
DIMENSION(:, :),
POINTER :: first_sgf
1949 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: zet
1951 CALL timeset(routinen, handle)
1953 cpassert(
SIZE(m_pq, 1) ==
SIZE(m_pq, 2))
1954 kind = bs_env%ri_rs%particle_set(
atom)%atomic_kind%kind_number
1955 CALL get_gto_basis_set(bs_env%basis_set_RI(kind)%gto_basis_set, &
1956 first_sgf=first_sgf, npgf=npgf, nset=nset, &
1957 nsgf_set=nsgf_set, zet=zet)
1959 DO i = first_sgf(1, iset), first_sgf(1, iset) + nsgf_set(iset) - 1
1960 m_pq(i, i) = m_pq(i, i) + &
1961 bs_env%regularization_RI* &
1962 max(1.0_dp, 1.0_dp/minval(zet(1:npgf(iset), iset)))
1966 CALL timestop(handle)
1968 END SUBROUTINE regularize_m_pq_block
1982 SUBROUTINE compute_optimized_ri_matrix_block( &
1983 bs_env, atom_U_a, atom_U_b, coulomb, symmetric, matrix_optimized)
1985 TYPE(optimized_atom_u_type),
INTENT(IN) :: atom_u_a, atom_u_b
1986 LOGICAL,
INTENT(IN) :: coulomb, symmetric
1987 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
1988 INTENT(OUT) :: matrix_optimized
1990 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_optimized_RI_matrix_block'
1992 INTEGER :: atom_a, atom_b, first_a, first_b, &
1993 handle, i, j, last_a, last_b, &
1994 nri_small_a, nri_small_b
1995 REAL(kind=
dp),
ALLOCATABLE :: matrix_pq_contribution(:, :), matrix_reference(:, :), &
1996 matrix_reference_times_u_b(:, :)
1998 CALL timeset(routinen, handle)
2000 nri_small_a =
SIZE(atom_u_a%U_Pp, 2)
2001 nri_small_b =
SIZE(atom_u_b%U_Pp, 2)
2003 cpassert(nri_small_a == nri_small_b)
2005 ALLOCATE (matrix_optimized(nri_small_a, nri_small_b), source=0.0_dp)
2006 DO i = 1,
SIZE(atom_u_a%ref_atom)
2007 atom_a = atom_u_a%ref_atom(i)
2008 first_a = atom_u_a%first_P(i)
2009 last_a = first_a + get_ref_ri_size(bs_env, atom_a) - 1
2010 DO j = 1,
SIZE(atom_u_b%ref_atom)
2011 IF (symmetric .AND. j > i) cycle
2012 atom_b = atom_u_b%ref_atom(j)
2013 first_b = atom_u_b%first_P(j)
2014 last_b = first_b + get_ref_ri_size(bs_env, atom_b) - 1
2016 CALL compute_m_pq_ab(bs_env, atom_a, atom_b, matrix_reference)
2018 CALL compute_m_pq_ab( &
2019 bs_env, atom_a, atom_b, matrix_reference, bs_env%ri_metric)
2020 IF (atom_a == atom_b .AND. bs_env%regularization_RI > 0.0_dp)
THEN
2021 CALL regularize_m_pq_block(bs_env, atom_a, matrix_reference)
2024 ALLOCATE (matrix_reference_times_u_b(
SIZE(matrix_reference, 1), nri_small_b))
2025 matrix_reference_times_u_b(:, :) = &
2026 matmul(matrix_reference, atom_u_b%U_Pp(first_b:last_b, :))
2027 ALLOCATE (matrix_pq_contribution(nri_small_a, nri_small_b))
2028 matrix_pq_contribution(:, :) = &
2029 matmul(transpose(atom_u_a%U_Pp(first_a:last_a, :)), &
2030 matrix_reference_times_u_b)
2031 matrix_optimized(:, :) = matrix_optimized + matrix_pq_contribution
2032 IF (symmetric .AND. i /= j)
THEN
2033 matrix_optimized(:, :) = matrix_optimized + transpose(matrix_pq_contribution)
2035 DEALLOCATE (matrix_pq_contribution, matrix_reference, matrix_reference_times_u_b)
2038 IF (.NOT. all(ieee_is_finite(matrix_optimized)))
THEN
2039 cpabort(
"AUTO_RI optimized metric block contains invalid values")
2042 CALL timestop(handle)
2044 END SUBROUTINE compute_optimized_ri_matrix_block
2054 SUBROUTINE compute_contracted_ri_matrix(qs_env, bs_env, lists, matrix_pq, coulomb)
2057 TYPE(ab_block_list_type),
DIMENSION(:),
INTENT(IN) :: lists
2059 LOGICAL,
INTENT(IN) :: coulomb
2061 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_contracted_RI_matrix'
2063 INTEGER :: handle, iatom, jatom, npcol, nprow, &
2064 pair_index, ri_size_opt
2065 INTEGER,
POINTER :: col_dist(:), row_dist(:), sizes_opt_ri(:)
2066 LOGICAL :: atom_u_a_ready
2067 REAL(kind=
dp),
ALLOCATABLE :: matrix_pq_block(:, :)
2071 TYPE(optimized_atom_u_type) :: atom_u_a, atom_u_b
2073 CALL timeset(routinen, handle)
2075 ALLOCATE (sizes_opt_ri(bs_env%n_atom), row_dist(bs_env%n_atom), col_dist(bs_env%n_atom))
2076 sizes_opt_ri(:) = bs_env%auto_ri%sizes_opt_RI
2079 DO iatom = 1,
SIZE(sizes_opt_ri)
2080 row_dist(iatom) = mod(iatom - 1, nprow)
2081 col_dist(iatom) = mod(iatom - 1, npcol)
2083 ri_size_opt = sum(sizes_opt_ri)
2084 CALL create_distributed_matrix(qs_env, matrix_pq, ri_size_opt, ri_size_opt)
2086 CALL dbcsr_create(blocks, name=
'AUTO_RI contracted metric', dist=dist, &
2087 matrix_type=dbcsr_type_symmetric, &
2088 row_blk_size=sizes_opt_ri, col_blk_size=sizes_opt_ri)
2091 DO iatom = 1,
SIZE(sizes_opt_ri)
2092 atom_u_a_ready = .false.
2094 pair_index = pair_index + 1
2095 IF (mod(pair_index - 1, bs_env%para_env%num_pe) /= bs_env%para_env%mepos) cycle
2096 IF (.NOT. atom_u_a_ready)
THEN
2097 CALL build_optimized_atom_u(bs_env, iatom, lists(iatom), atom_u_a)
2098 atom_u_a_ready = .true.
2100 IF (iatom == jatom)
THEN
2101 CALL compute_optimized_ri_matrix_block( &
2102 bs_env, atom_u_a, atom_u_a, coulomb, .true., &
2104 matrix_pq_block(:, :) = 0.5_dp*(matrix_pq_block + transpose(matrix_pq_block))
2106 CALL build_optimized_atom_u(bs_env, jatom, lists(jatom), atom_u_b)
2107 CALL compute_optimized_ri_matrix_block( &
2108 bs_env, atom_u_a, atom_u_b, coulomb, .false., &
2112 DEALLOCATE (matrix_pq_block)
2119 DEALLOCATE (sizes_opt_ri, row_dist, col_dist)
2121 CALL timestop(handle)
2123 END SUBROUTINE compute_contracted_ri_matrix
2134 SUBROUTINE compute_m_pq_inv(qs_env, bs_env, M_pq)
2139 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_M_pq_inv'
2141 INTEGER :: handle, ncol_local, nrow_local, &
2143 INTEGER,
DIMENSION(:),
POINTER :: col_indices, row_indices
2144 REAL(kind=
dp),
ALLOCATABLE :: eigenval(:), factors(:)
2145 REAL(kind=
dp),
CONTIGUOUS,
DIMENSION(:, :), &
2146 POINTER :: m_pq_aa_local, m_pq_local
2149 CALL timeset(routinen, handle)
2151 ri_size_opt = sum(bs_env%auto_ri%sizes_opt_RI)
2152 CALL create_distributed_matrix(qs_env, bs_env%auto_ri%M_pq_inv, &
2153 ri_size_opt, ri_size_opt)
2154 CALL create_distributed_matrix(qs_env, x_pq, ri_size_opt, ri_size_opt)
2155 CALL create_distributed_matrix(qs_env, m_pq_aa, ri_size_opt, ri_size_opt)
2156 CALL create_distributed_matrix(qs_env, work, ri_size_opt, ri_size_opt)
2157 CALL cp_fm_get_info(m_pq, nrow_local=nrow_local, ncol_local=ncol_local, &
2158 row_indices=row_indices, col_indices=col_indices, &
2159 local_data=m_pq_local)
2161 m_pq_aa_local = 0.0_dp
2162 CALL copy_m_pq_aa_blocks(m_pq_local(:nrow_local, :ncol_local), &
2163 m_pq_aa_local(:nrow_local, :ncol_local), &
2164 row_indices(:nrow_local), col_indices(:ncol_local), &
2165 bs_env%auto_ri%sizes_opt_RI)
2167 ALLOCATE (eigenval(ri_size_opt))
2168 CALL cp_fm_geeig(m_pq, m_pq_aa, x_pq, eigenval, work)
2169 CALL compute_optimized_m_pq_inv_factors(eigenval, factors)
2171 CALL cp_fm_syrk(
"U",
"N", ri_size_opt, 1.0_dp, x_pq, 1, 1, 0.0_dp, &
2172 bs_env%auto_ri%M_pq_inv)
2175 DEALLOCATE (eigenval, factors)
2180 CALL timestop(handle)
2182 END SUBROUTINE compute_m_pq_inv
2189 SUBROUTINE compute_m_pq_inv_and_v_pq(qs_env, bs_env)
2193 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_M_pq_inv_and_V_pq'
2196 TYPE(ab_block_list_type),
ALLOCATABLE :: lists(:)
2199 CALL timeset(routinen, handle)
2201 CALL build_ab_block_lists(bs_env, lists)
2202 CALL initialize_auto_ri_integrals(bs_env)
2203 CALL compute_contracted_ri_matrix(qs_env, bs_env, lists, m_pq, .false.)
2204 CALL compute_m_pq_inv(qs_env, bs_env, m_pq)
2206 CALL compute_contracted_ri_matrix(qs_env, bs_env, lists, bs_env%auto_ri%V_pq, .true.)
2209 CALL set_optimized_ri_basis_sizes(bs_env)
2211 CALL timestop(handle)
2213 END SUBROUTINE compute_m_pq_inv_and_v_pq
2224 SUBROUTINE compute_int_3c(ao_basis, ri_basis, potential, M_PQ, Int_3c)
2225 TYPE(gto_basis_set_type),
INTENT(IN) :: ao_basis, ri_basis
2227 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2229 REAL(kind=
dp),
INTENT(OUT) :: int_3c(:, :, :)
2231 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_int_3c'
2233 INTEGER :: handle, iset, jset, kset, max_ao_l, &
2234 max_l, nao, ncoa, ncob, ncoc, nri, &
2235 nsgfa, nsgfb, nsgfc, sgfa, sgfb, sgfc
2236 INTEGER,
DIMENSION(:),
POINTER :: lmax_a, lmax_c, lmin_a, lmin_c, npgf_a, &
2237 npgf_c, nsgf_set_a, nsgf_set_c
2238 INTEGER,
DIMENSION(:, :),
POINTER :: first_sgf_a, first_sgf_c
2239 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: int_2c_cart, int_2c_spherical
2240 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: int_3c_cart, int_3c_spherical_all, &
2241 int_3c_spherical_block
2242 REAL(kind=
dp),
DIMENSION(3) :: center
2243 REAL(kind=
dp),
DIMENSION(:),
POINTER :: radius_a, radius_b, radius_c
2244 REAL(kind=
dp),
DIMENSION(:, :),
POINTER :: pgf_radius_a, pgf_radius_c, sphi_a, &
2245 sphi_c, zeta_a, zeta_c
2248 CALL timeset(routinen, handle)
2250 CALL get_gto_basis_set(ao_basis, nsgf=nao, lmax=lmax_a, lmin=lmin_a, &
2251 npgf=npgf_a, nsgf_set=nsgf_set_a, first_sgf=first_sgf_a, &
2252 pgf_radius=pgf_radius_a, sphi=sphi_a, zet=zeta_a)
2253 CALL get_gto_basis_set(ri_basis, nsgf=nri, lmax=lmax_c, lmin=lmin_c, &
2254 npgf=npgf_c, nsgf_set=nsgf_set_c, first_sgf=first_sgf_c, &
2255 pgf_radius=pgf_radius_c, sphi=sphi_c, zet=zeta_c)
2256 cpassert(nao > 0 .AND. nri > 0)
2257 max_ao_l = maxval(lmax_a)
2258 max_l = max(max_ao_l, maxval(lmax_c))
2264 CALL cp_abort(__location__, &
2265 "AUTO_RI TRUNCATED fitting requires LIBINT for "// &
2266 "COULOMB_2C and COULOMB_3C")
2274 ALLOCATE (m_pq(nri, nri), int_3c_spherical_all(nao, nao, nri))
2276 int_3c_spherical_all = 0.0_dp
2278 DO iset = 1, ri_basis%nset
2279 ncoa = npgf_c(iset)*
ncoset(lmax_c(iset))
2280 sgfa = first_sgf_c(1, iset)
2281 nsgfa = nsgf_set_c(iset)
2282 radius_a => pgf_radius_c(1:npgf_c(iset), iset)
2283 DO jset = 1, ri_basis%nset
2284 ncob = npgf_c(jset)*
ncoset(lmax_c(jset))
2285 sgfb = first_sgf_c(1, jset)
2286 nsgfb = nsgf_set_c(jset)
2287 radius_b => pgf_radius_c(1:npgf_c(jset), jset)
2288 ALLOCATE (int_2c_cart(ncoa, ncob), int_2c_spherical(nsgfa, nsgfb))
2289 int_2c_cart = 0.0_dp
2291 lmin_c(jset), lmax_c(jset), &
2292 npgf_c(iset), npgf_c(jset), zeta_c(1:npgf_c(iset), iset), &
2293 zeta_c(1:npgf_c(jset), jset), &
2294 radius_a, radius_b, center, center, int_2c_cart, potential)
2295 CALL ab_contract(int_2c_spherical, int_2c_cart, sphi_c(:, sgfa:), sphi_c(:, sgfb:), &
2296 ncoa, ncob, nsgfa, nsgfb)
2297 m_pq(sgfa:sgfa + nsgfa - 1, sgfb:sgfb + nsgfb - 1) = int_2c_spherical
2298 DEALLOCATE (int_2c_spherical, int_2c_cart)
2302 DO iset = 1, ao_basis%nset
2303 ncoa = npgf_a(iset)*
ncoset(lmax_a(iset))
2304 sgfa = first_sgf_a(1, iset)
2305 nsgfa = nsgf_set_a(iset)
2306 radius_a => pgf_radius_a(1:npgf_a(iset), iset)
2307 DO jset = 1, ao_basis%nset
2308 ncob = npgf_a(jset)*
ncoset(lmax_a(jset))
2309 sgfb = first_sgf_a(1, jset)
2310 nsgfb = nsgf_set_a(jset)
2311 radius_b => pgf_radius_a(1:npgf_a(jset), jset)
2312 DO kset = 1, ri_basis%nset
2313 ncoc = npgf_c(kset)*
ncoset(lmax_c(kset))
2314 sgfc = first_sgf_c(1, kset)
2315 nsgfc = nsgf_set_c(kset)
2316 radius_c => pgf_radius_c(1:npgf_c(kset), kset)
2317 ALLOCATE (int_3c_cart(ncoa, ncob, ncoc), &
2318 int_3c_spherical_block(nsgfa, nsgfb, nsgfc))
2319 int_3c_cart = 0.0_dp
2321 lmin_a(jset), lmax_a(jset), &
2322 lmin_c(kset), lmax_c(kset), npgf_a(iset), npgf_a(jset), &
2323 npgf_c(kset), zeta_a(1:npgf_a(iset), iset), &
2324 zeta_a(1:npgf_a(jset), jset), zeta_c(1:npgf_c(kset), kset), &
2325 radius_a, radius_b, radius_c, center, center, center, &
2326 int_3c_cart, potential)
2327 CALL abc_contract(int_3c_spherical_block, int_3c_cart, &
2328 sphi_a(:, sgfa:), sphi_a(:, sgfb:), &
2329 sphi_c(:, sgfc:), ncoa, ncob, ncoc, nsgfa, nsgfb, nsgfc)
2330 int_3c_spherical_all(sgfa:sgfa + nsgfa - 1, sgfb:sgfb + nsgfb - 1, &
2331 sgfc:sgfc + nsgfc - 1) = int_3c_spherical_block
2332 DEALLOCATE (int_3c_spherical_block, int_3c_cart)
2337 int_3c(:, :, :) = int_3c_spherical_all
2339 IF (.NOT. all(ieee_is_finite(m_pq)))
THEN
2340 cpabort(
"AUTO_RI metric contains invalid values")
2342 IF (.NOT. all(ieee_is_finite(int_3c)))
THEN
2343 cpabort(
"AUTO_RI three-center integrals contain invalid values")
2346 CALL timestop(handle)
2348 END SUBROUTINE compute_int_3c
2354 SUBROUTINE initialize_auto_ri_integrals(bs_env)
2357 CHARACTER(LEN=*),
PARAMETER :: routinen =
'initialize_auto_ri_integrals'
2359 CHARACTER(LEN=default_path_length) :: table_file
2360 INTEGER :: handle, ikind, max_l, table_lmax, unit_id
2362 CALL timeset(routinen, handle)
2365 DO ikind = 1,
SIZE(bs_env%basis_set_RI)
2366 cpassert(
ASSOCIATED(bs_env%basis_set_RI(ikind)%gto_basis_set))
2367 max_l = max(max_l, maxval(bs_env%basis_set_RI(ikind)%gto_basis_set%lmax))
2375 table_lmax = 2*max_l + 1
2378 IF (bs_env%para_env%is_source())
THEN
2380 CALL open_file(unit_number=unit_id, file_name=trim(table_file))
2382 CALL init_t_c_g0(table_lmax, unit_id, bs_env%para_env%mepos, bs_env%para_env)
2383 IF (bs_env%para_env%is_source())
CALL close_file(unit_id)
2387 CALL timestop(handle)
2389 END SUBROUTINE initialize_auto_ri_integrals
2399 SUBROUTINE compute_m_pq_ab(bs_env, atom_A, atom_B, M_PQ, ri_potential)
2401 INTEGER,
INTENT(IN) :: atom_a, atom_b
2402 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2404 TYPE(libint_potential_type),
INTENT(IN),
OPTIONAL :: ri_potential
2406 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_M_PQ_AB'
2408 INTEGER :: atom_1, atom_2, handle, kind_1, kind_2
2409 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :) :: m_pq_canonical
2410 TYPE(libint_potential_type) :: potential
2412 CALL timeset(routinen, handle)
2414 cpassert(
ASSOCIATED(bs_env%ri_rs%particle_set))
2415 cpassert(atom_a >= 1 .AND. atom_a <= bs_env%n_atom)
2416 cpassert(atom_b >= 1 .AND. atom_b <= bs_env%n_atom)
2417 IF (atom_a >= atom_b)
THEN
2424 kind_1 = bs_env%ri_rs%particle_set(atom_1)%atomic_kind%kind_number
2425 kind_2 = bs_env%ri_rs%particle_set(atom_2)%atomic_kind%kind_number
2427 IF (
PRESENT(ri_potential))
THEN
2429 potential = ri_potential
2433 CALL compute_m_pq( &
2434 basis_a=bs_env%basis_set_RI(kind_1)%gto_basis_set, &
2435 basis_b=bs_env%basis_set_RI(kind_2)%gto_basis_set, &
2436 center_a=bs_env%ri_rs%particle_set(atom_1)%r, &
2437 center_b=bs_env%ri_rs%particle_set(atom_2)%r, &
2438 potential=potential, m_pq=m_pq_canonical)
2440 IF (atom_a >= atom_b)
THEN
2441 CALL move_alloc(m_pq_canonical, m_pq)
2443 ALLOCATE (m_pq(
SIZE(m_pq_canonical, 2),
SIZE(m_pq_canonical, 1)))
2444 m_pq(:, :) = transpose(m_pq_canonical)
2445 DEALLOCATE (m_pq_canonical)
2448 CALL timestop(handle)
2450 END SUBROUTINE compute_m_pq_ab
2461 SUBROUTINE compute_m_pq(basis_a, basis_b, center_a, center_b, potential, M_PQ)
2462 TYPE(gto_basis_set_type),
POINTER :: basis_a, basis_b
2463 REAL(kind=
dp),
DIMENSION(3),
INTENT(IN) :: center_a, center_b
2464 TYPE(libint_potential_type),
INTENT(IN) :: potential
2465 REAL(kind=
dp),
ALLOCATABLE,
DIMENSION(:, :), &
2468 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_M_PQ'
2472 CALL timeset(routinen, handle)
2474 ALLOCATE (m_pq(basis_a%nsgf, basis_b%nsgf), source=0.0_dp)
2475 SELECT CASE (potential%potential_type)
2478 fba=basis_a, fbb=basis_b, &
2479 r_cutoff=potential%cutoff_radius, calculate_forces=.false.)
2482 fba=basis_a, fbb=basis_b, calculate_forces=.false.)
2484 cpabort(
"AUTO_RI two-center metric requires COULOMB or TRUNCATED")
2487 CALL timestop(handle)
2489 END SUBROUTINE compute_m_pq
2497 INTEGER FUNCTION get_ref_ri_size(bs_env, iatom)
RESULT(nRI_ref)
2499 INTEGER,
INTENT(IN) :: iatom
2503 ikind = bs_env%ri_rs%particle_set(iatom)%atomic_kind%kind_number
2504 nri_ref = bs_env%basis_set_RI(ikind)%gto_basis_set%nsgf
2506 END FUNCTION get_ref_ri_size
static GRID_HOST_DEVICE int modulo(int a, int m)
Equivalent of Fortran's MODULO, which always return a positive number. https://gcc....
Contraction of integrals over primitive Cartesian Gaussians based on the contraction matrix sphi whic...
subroutine, public abc_contract(abcint, sabc, sphi_a, sphi_b, sphi_c, ncoa, ncob, ncoc, nsgfa, nsgfb, nsgfc)
contract three-center overlap integrals (a,b,c) and transfer to spherical Gaussians
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_atomic_kind_set(atomic_kind_set, atom_of_kind, kind_of, natom_of_kind, maxatom, natom, nshell, fist_potential_present, shell_present, shell_adiabatic, shell_check_distance, damping_present)
Get attributes of an atomic kind set.
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)
...
constants for the different operators of the 2c-integrals
integer, parameter, public operator_truncated
integer, parameter, public operator_coulomb
Common interface for two- and three-center Coulomb integrals.
subroutine, public coulomb_integral_cleanup(context)
Release the engines initialized in a Coulomb integral context.
subroutine, public compute_coulomb_3c(context, la_min, la_max, lb_min, lb_max, lc_min, lc_max, npgfa, npgfb, npgfc, zeta, zetb, zetc, rpgfa, rpgfb, rpgfc, ra, rb, rc, habc, potential_parameter)
Evaluate one uncontracted three-center Coulomb integral block.
subroutine, public coulomb_integral_init(context, max_am_2c, max_am_3c)
Initialize the engines needed by the requested Coulomb integral operations.
subroutine, public compute_coulomb_2c(context, la_min, la_max, lb_min, lb_max, npgfa, npgfb, zeta, zetb, rpgfa, rpgfb, ra, rb, hab, potential_parameter)
Evaluate one uncontracted two-center Coulomb integral block.
methods related to the blacs parallel environment
subroutine, public dbcsr_distribution_release(dist)
...
subroutine, public dbcsr_distribution_new(dist, template, group, pgrid, row_dist, col_dist, reuse_arrays)
...
subroutine, public dbcsr_finalize(matrix)
...
subroutine, public dbcsr_release(matrix)
...
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)
...
DBCSR operations in CP2K.
subroutine, public copy_dbcsr_to_fm(matrix, fm)
Copy a DBCSR matrix to a BLACS matrix.
Utility routines to open and close files. Tracking of preconnections.
subroutine, public open_file(file_name, file_status, file_form, file_action, file_position, file_pad, unit_number, debug, skip_get_unit_number, file_access)
Opens the requested file using a free unit number.
character(len=default_path_length) function, public discover_file(file_name)
Checks various locations for a file name.
subroutine, public close_file(unit_number, file_status, keep_preconnection)
Close an open file given by its logical unit number. Optionally, keep the file and unit preconnected.
Basic linear algebra operations for full matrices.
subroutine, public cp_fm_column_scale(matrixa, scaling)
scales column i of matrix a with scaling(i)
subroutine, public cp_fm_syrk(uplo, trans, k, alpha, matrix_a, ia, ja, beta, matrix_c)
performs a rank-k update of a symmetric matrix_c matrix_c = beta * matrix_c + alpha * matrix_a * tran...
subroutine, public cp_fm_uplo_to_full(matrix, work, uplo)
given a triangular matrix according to uplo, computes the corresponding full matrix
used for collecting some of the diagonalization schemes available for cp_fm_type. cp_fm_power also mo...
subroutine, public cp_fm_geeig(amatrix, bmatrix, eigenvectors, eigenvalues, work)
General Eigenvalue Problem AX = BXE. Use cuSOLVERMp directly when requested and large enough; otherwi...
represent the structure of a full matrix
subroutine, public cp_fm_struct_create(fmstruct, para_env, context, nrow_global, ncol_global, nrow_block, ncol_block, descriptor, first_p_pos, local_leading_dimension, template_fmstruct, square_blocks, force_block)
allocates and initializes a full matrix structure
subroutine, public cp_fm_struct_release(fmstruct)
releases a full matrix structure
represent a full matrix distributed on many processors
subroutine, public cp_fm_get_info(matrix, name, nrow_global, ncol_global, nrow_block, ncol_block, nrow_local, ncol_local, row_indices, col_indices, local_data, context, nrow_locals, ncol_locals, matrix_struct, para_env)
returns all kind of information about the full matrix
subroutine, public cp_fm_create(matrix, matrix_struct, name, nrow, ncol, set_zero)
creates a new full matrix with the given structure
subroutine, public cp_fm_get_submatrix(fm, target_m, start_row, start_col, n_rows, n_cols, transpose)
gets a submatrix of a full matrix op(target_m)(1:n_rows,1:n_cols) =fm(start_row:start_row+n_rows,...
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.
Automatic RI basis set optimization for molecular GW.
subroutine, public generate_auto_ri_basis(qs_env, bs_env)
Executes the AUTO_RI algorithm defined by Eqs. (1)-(14).
Input and persistent data for automatic RI basis optimization.
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,...
Library choices for electronic integral APIs.
type(integral_library_type), save, public active_integral_library
integer, parameter, public library_libint
Defines the basic variable types.
integer, parameter, public dp
integer, parameter, public default_path_length
2- and 3-center electron repulsion integral routines based on libint2 Currently available operators: ...
An array-based list which grows on demand. When the internal array is full, a new array of twice the ...
integer, parameter, public local_gemm_pu_host
Machine interface based on Fortran 2003 and POSIX.
real(kind=dp) function, public m_walltime()
returns time from a real-time clock, protected against rolling early/easily
Collection of simple mathematical functions and subroutines.
subroutine, public diamat_all(a, eigval, dac)
Diagonalize the symmetric n by n matrix a using the LAPACK library. Only the upper triangle of matrix...
Interface to the message passing library MPI.
Provides Cartesian and spherical orbital pointers and indices.
subroutine, public init_orbital_pointers(maxl)
Initialize or update the orbital pointers.
integer, dimension(:), allocatable, public ncoset
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.
This module computes the basic integrals for the truncated coulomb operator.
subroutine, public init(nder, iunit, mepos, group)
...
integer function, public get_lmax_init()
Returns the value of nderiv_init so that one can check if opening the potential file is worhtwhile.
All kind of helpful little routines.
represent a blacs multidimensional parallel environment (for the mpi corrispective see cp_paratypes/m...
keeps the information about the structure of a full matrix
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