9
1
mirror of https://github.com/QuantumPackage/qp2.git synced 2024-12-26 21:33:30 +01:00
qp2/src/mo_two_e_ints/map_integrals_complex.irp.f
2020-02-11 18:23:34 -06:00

495 lines
15 KiB
Fortran

use map_module
subroutine insert_into_mo_integrals_map_2(n_integrals, &
buffer_i, buffer_values, thr)
use map_module
implicit none
BEGIN_DOC
! Create new entry into MO map, or accumulate in an existing entry
END_DOC
integer, intent(in) :: n_integrals
integer(key_kind), intent(inout) :: buffer_i(n_integrals)
real(integral_kind), intent(inout) :: buffer_values(n_integrals)
real(integral_kind), intent(in) :: thr
call map_update(mo_integrals_map_2, buffer_i, buffer_values, n_integrals, thr)
end
BEGIN_PROVIDER [ complex*16, mo_integrals_cache_complex, (0_8:128_8*128_8*128_8*128_8) ]
implicit none
BEGIN_DOC
! Cache of MO integrals for fast access
END_DOC
PROVIDE mo_two_e_integrals_in_map
integer*8 :: i,j,k,l
integer*4 :: i4,j4,k4,l4
integer*8 :: ii
integer(key_kind) :: idx
complex(integral_kind) :: integral
complex*16 :: get_two_e_integral_complex_simple
FREE ao_integrals_cache
!$OMP PARALLEL DO PRIVATE (i,j,k,l,i4,j4,k4,l4,idx,ii,integral)
do l=mo_integrals_cache_min_8,mo_integrals_cache_max_8
l4 = int(l,4)
do k=mo_integrals_cache_min_8,mo_integrals_cache_max_8
k4 = int(k,4)
do j=mo_integrals_cache_min_8,mo_integrals_cache_max_8
j4 = int(j,4)
do i=mo_integrals_cache_min_8,mo_integrals_cache_max_8
i4 = int(i,4)
!DIR$ FORCEINLINE
integral = get_two_e_integral_complex_simple(i,j,k,l,&
mo_integrals_map,mo_integrals_map_2)
ii = l-mo_integrals_cache_min_8
ii = ior( shiftl(ii,7), k-mo_integrals_cache_min_8)
ii = ior( shiftl(ii,7), j-mo_integrals_cache_min_8)
ii = ior( shiftl(ii,7), i-mo_integrals_cache_min_8)
mo_integrals_cache_complex(ii) = integral
enddo
enddo
enddo
enddo
!$OMP END PARALLEL DO
END_PROVIDER
complex*16 function get_two_e_integral_complex_simple(i,j,k,l,map,map2) result(result)
use map_module
implicit none
BEGIN_DOC
! Gets one MO bi-electronic integral from the MO map
! reuse ao map/idx/sign function
END_DOC
integer, intent(in) :: i,j,k,l
integer(key_kind) :: idx
real(integral_kind) :: tmp_re, tmp_im
type(map_type), intent(inout) :: map,map2
complex(integral_kind) :: tmp
logical :: use_map1
double precision :: sign
PROVIDE mo_two_e_integrals_in_map
call ao_two_e_integral_complex_map_idx_sign(i,j,k,l,use_map1,idx,sign)
if (use_map1) then
call map_get(map,idx,tmp_re)
call map_get(map,idx+1,tmp_im)
tmp_im *= sign
else
call map_get(map2,idx,tmp_re)
if (sign/=0.d0) then
call map_get(map2,idx+1,tmp_im)
tmp_im *= sign
else
tmp_im=0.d0
endif
endif
tmp = dcmplx(tmp_re,tmp_im)
result = tmp
end
complex*16 function get_two_e_integral_complex(i,j,k,l,map,map2)
use map_module
implicit none
BEGIN_DOC
! Returns one integral <ij|kl> in the MO basis
! TODO: finish this
END_DOC
integer, intent(in) :: i,j,k,l
integer(key_kind) :: idx
integer :: ii
integer*8 :: ii_8
type(map_type), intent(inout) :: map,map2
complex(integral_kind) :: tmp
complex(integral_kind) :: get_two_e_integral_complex_simple
PROVIDE mo_two_e_integrals_in_map mo_integrals_cache_complex
ii = l-mo_integrals_cache_min
ii = ior(ii, k-mo_integrals_cache_min)
ii = ior(ii, j-mo_integrals_cache_min)
ii = ior(ii, i-mo_integrals_cache_min)
if (iand(ii, -128) /= 0) then
tmp = get_two_e_integral_complex_simple(i,j,k,l,map,map2)
else
ii_8 = int(l,8)-mo_integrals_cache_min_8
ii_8 = ior( shiftl(ii_8,7), int(k,8)-mo_integrals_cache_min_8)
ii_8 = ior( shiftl(ii_8,7), int(j,8)-mo_integrals_cache_min_8)
ii_8 = ior( shiftl(ii_8,7), int(i,8)-mo_integrals_cache_min_8)
tmp = mo_integrals_cache_complex(ii_8)
endif
get_two_e_integral_complex = tmp
end
complex*16 function mo_two_e_integral_complex(i,j,k,l)
implicit none
BEGIN_DOC
! Returns one integral <ij|kl> in the MO basis
END_DOC
integer, intent(in) :: i,j,k,l
complex*16 :: get_two_e_integral_complex
PROVIDE mo_two_e_integrals_in_map mo_integrals_cache_complex
PROVIDE mo_two_e_integrals_in_map
!DIR$ FORCEINLINE
mo_two_e_integral_complex = get_two_e_integral_complex(i,j,k,l,mo_integrals_map,mo_integrals_map_2)
return
end
subroutine get_mo_two_e_integrals_complex(j,k,l,sze,out_val,map,map2)
use map_module
implicit none
BEGIN_DOC
! Returns multiple integrals <ij|kl> in the MO basis, all
! i for j,k,l fixed.
END_DOC
integer, intent(in) :: j,k,l, sze
complex*16, intent(out) :: out_val(sze)
type(map_type), intent(inout) :: map,map2
integer :: i
complex*16, external :: get_two_e_integral_complex_simple
integer :: ii, ii0
integer*8 :: ii_8, ii0_8
complex(integral_kind) :: tmp
integer(key_kind) :: i1, idx
integer(key_kind) :: p,q,r,s,i2
PROVIDE mo_two_e_integrals_in_map mo_integrals_cache_complex
!DEBUG
! do i=1,sze
! out_val(i) = get_two_e_integral_complex(i,j,k,l,map,map2)
! enddo
! return
!DEBUG
ii0 = l-mo_integrals_cache_min
ii0 = ior(ii0, k-mo_integrals_cache_min)
ii0 = ior(ii0, j-mo_integrals_cache_min)
ii0_8 = int(l,8)-mo_integrals_cache_min_8
ii0_8 = ior( shiftl(ii0_8,7), int(k,8)-mo_integrals_cache_min_8)
ii0_8 = ior( shiftl(ii0_8,7), int(j,8)-mo_integrals_cache_min_8)
do i=1,sze
ii = ior(ii0, i-mo_integrals_cache_min)
if (iand(ii, -128) == 0) then
ii_8 = ior( shiftl(ii0_8,7), int(i,8)-mo_integrals_cache_min_8)
out_val(i) = mo_integrals_cache_complex(ii_8)
else
out_val(i) = get_two_e_integral_complex_simple(i,j,k,l,map,map2)
endif
enddo
end
!subroutine get_mo_two_e_integrals_ij_complex(k,l,sze,out_array,map)
! use map_module
! implicit none
! BEGIN_DOC
! ! Returns multiple integrals <ij|kl> in the MO basis, all
! ! i(1)j(2) 1/r12 k(1)l(2)
! ! i, j for k,l fixed.
! END_DOC
! integer, intent(in) :: k,l, sze
! double precision, intent(out) :: out_array(sze,sze)
! type(map_type), intent(inout) :: map
! integer :: i,j,kk,ll,m
! integer(key_kind),allocatable :: hash(:)
! integer ,allocatable :: pairs(:,:), iorder(:)
! real(integral_kind), allocatable :: tmp_val(:)
!
! PROVIDE mo_two_e_integrals_in_map
! allocate (hash(sze*sze), pairs(2,sze*sze),iorder(sze*sze), &
! tmp_val(sze*sze))
!
! kk=0
! out_array = 0.d0
! do j=1,sze
! do i=1,sze
! kk += 1
! !DIR$ FORCEINLINE
! call two_e_integrals_index(i,j,k,l,hash(kk))
! pairs(1,kk) = i
! pairs(2,kk) = j
! iorder(kk) = kk
! enddo
! enddo
!
! logical :: integral_is_in_map
! if (key_kind == 8) then
! call i8radix_sort(hash,iorder,kk,-1)
! else if (key_kind == 4) then
! call iradix_sort(hash,iorder,kk,-1)
! else if (key_kind == 2) then
! call i2radix_sort(hash,iorder,kk,-1)
! endif
!
! call map_get_many(mo_integrals_map, hash, tmp_val, kk)
!
! do ll=1,kk
! m = iorder(ll)
! i=pairs(1,m)
! j=pairs(2,m)
! out_array(i,j) = tmp_val(ll)
! enddo
!
! deallocate(pairs,hash,iorder,tmp_val)
!end
!subroutine get_mo_two_e_integrals_i1j1_complex(k,l,sze,out_array,map)
! use map_module
! implicit none
! BEGIN_DOC
! ! Returns multiple integrals <ik|jl> in the MO basis, all
! ! i(1)j(1) 1/r12 k(2)l(2)
! ! i, j for k,l fixed.
! END_DOC
! integer, intent(in) :: k,l, sze
! double precision, intent(out) :: out_array(sze,sze)
! type(map_type), intent(inout) :: map
! integer :: i,j,kk,ll,m
! integer(key_kind),allocatable :: hash(:)
! integer ,allocatable :: pairs(:,:), iorder(:)
! real(integral_kind), allocatable :: tmp_val(:)
!
! PROVIDE mo_two_e_integrals_in_map
! allocate (hash(sze*sze), pairs(2,sze*sze),iorder(sze*sze), &
! tmp_val(sze*sze))
!
! kk=0
! out_array = 0.d0
! do j=1,sze
! do i=1,sze
! kk += 1
! !DIR$ FORCEINLINE
! call two_e_integrals_index(i,k,j,l,hash(kk))
! pairs(1,kk) = i
! pairs(2,kk) = j
! iorder(kk) = kk
! enddo
! enddo
!
! logical :: integral_is_in_map
! if (key_kind == 8) then
! call i8radix_sort(hash,iorder,kk,-1)
! else if (key_kind == 4) then
! call iradix_sort(hash,iorder,kk,-1)
! else if (key_kind == 2) then
! call i2radix_sort(hash,iorder,kk,-1)
! endif
!
! call map_get_many(mo_integrals_map, hash, tmp_val, kk)
!
! do ll=1,kk
! m = iorder(ll)
! i=pairs(1,m)
! j=pairs(2,m)
! out_array(i,j) = tmp_val(ll)
! enddo
!
! deallocate(pairs,hash,iorder,tmp_val)
!end
subroutine get_mo_two_e_integrals_coulomb_ii_complex(k,l,sze,out_val,map,map2)
use map_module
implicit none
BEGIN_DOC
! Returns multiple integrals <ki|li>
! k(1)i(2) 1/r12 l(1)i(2) :: out_val(i1)
! for k,l fixed.
! real and in map2 if k==l
! complex and in map1 otherwise
! take conjugate if k>l
! TODO: determine best way to structure code
! to account for single/double integral_kind, real/complex, and +/- imag part
END_DOC
integer, intent(in) :: k,l, sze
complex*16, intent(out) :: out_val(sze)
type(map_type), intent(inout) :: map,map2
integer :: i
integer(key_kind) :: hash(sze),hash_re(sze),hash_im(sze)
real(integral_kind) :: tmp_re(sze),tmp_im(sze)
double precision :: out_re(sze),out_im(sze)
double precision :: sign
PROVIDE mo_two_e_integrals_in_map
if (k.eq.l) then ! real, call other function
call get_mo_two_e_integrals_coulomb_ijij_complex(k,sze,out_re,map2)
do i=1,sze
out_val(i) = dcmplx(out_re(i),0.d0)
enddo
else ! complex
if (k.gt.l) then
sign = -1.d0
else
sign = 1.d0
endif
do i=1,sze
!DIR$ FORCEINLINE
call two_e_integrals_index(k,i,l,i,hash(i))
!hash_im(i) = hash(i)*2
hash_im(i) = shiftl(hash(i),1)
hash_re(i) = hash_im(i)-1
enddo
if (integral_kind == 8) then
call map_get_many(map, hash_re, out_re, sze)
call map_get_many(map, hash_im, out_im, sze)
do i=1,sze
out_val(i) = dcmplx(out_re(i),sign*out_im(i))
enddo
else
call map_get_many(map, hash_re, tmp_re, sze)
call map_get_many(map, hash_im, tmp_im, sze)
! Conversion to double complex
do i=1,sze
out_val(i) = dcmplx(tmp_re(i),sign*tmp_im(i))
enddo
endif
endif
end
subroutine get_mo_two_e_integrals_coulomb_ijij_complex(j,sze,out_val,map2)
use map_module
implicit none
BEGIN_DOC
! Returns multiple integrals <ij|ij>
! i*(1)j*(2) 1/r12 i(1)j(2) :: out_val(i)
! for j fixed.
! always in map2, always real
END_DOC
integer, intent(in) :: j, sze
double precision, intent(out) :: out_val(sze)
type(map_type), intent(inout) :: map2
integer :: i
integer(key_kind) :: hash(sze),hash_re(sze)
real(integral_kind) :: tmp_re(sze)
PROVIDE mo_two_e_integrals_in_map
do i=1,sze
!DIR$ FORCEINLINE
call two_e_integrals_index(i,j,i,j,hash(i))
!hash_re(i) = hash(i)*2 - 1
hash_re(i) = shiftl(hash(i),1) - 1
enddo
if (integral_kind == 8) then
call map_get_many(map2, hash_re, out_val, sze)
else
call map_get_many(map2, hash_re, tmp_re, sze)
! Conversion to double complex
do i=1,sze
out_val(i) = dble(tmp_re(i))
enddo
endif
end
subroutine get_mo_two_e_integrals_exch_ii_complex(k,l,sze,out_val,map,map2)
use map_module
implicit none
BEGIN_DOC
! Returns multiple integrals <ki|il>
! k*(1)i*(2) 1/r12 i(1)l(2) :: out_val(i1)
! for k,l fixed.
!
! if k<l, then:
! i < k map2 +
! k <= i <= l map1 +
! l < i map2 -
!
! if l<k, then same maps as above, but take complex conjugate
END_DOC
integer, intent(in) :: k,l, sze
double precision, intent(out) :: out_val(sze)
type(map_type), intent(inout) :: map,map2
integer :: i,klmin,klmax
integer(key_kind) :: hash(sze),hash_re(sze),hash_im(sze)
real(integral_kind) :: tmp_re(sze),tmp_im(sze)
double precision :: out_re(sze),out_im(sze)
double precision :: sign,sign2(sze)
PROVIDE mo_two_e_integrals_in_map
if (k.eq.l) then ! real, call other function
call get_mo_two_e_integrals_exch_ijji_complex(k,sze,out_re,map,map2)
do i=1,sze
out_val(i) = dcmplx(out_re(i),0.d0)
enddo
else ! complex
if (k.gt.l) then
sign = -1.d0
else
sign = 1.d0
endif
klmin = min(k,l) ! put these in conditional above?
klmax = max(k,l)
sign2(1:klmax) = 1.d0
sign2(klmax+1:sze) = -1.d0
do i=1,sze
!DIR$ FORCEINLINE
call two_e_integrals_index(k,i,i,l,hash(i))
!hash_im(i) = hash(i)*2
hash_im(i) = shiftl(hash(i),1)
hash_re(i) = hash_im(i)-1
enddo
if (integral_kind == 8) then
call map_get_many(map2, hash_re(1:klmin-1), out_re(1:klmin-1), klmin-1)
call map_get_many(map2, hash_im(1:klmin-1), out_im(1:klmin-1), klmin-1)
call map_get_many(map, hash_re(klmin:klmax), out_re(klmin:klmax), klmax-klmin+1)
call map_get_many(map, hash_im(klmin:klmax), out_im(klmin:klmax), klmax-klmin+1)
call map_get_many(map2, hash_re(klmax+1:sze), out_re(klmax+1:sze), sze-klmax)
call map_get_many(map2, hash_im(klmax+1:sze), out_im(klmax+1:sze), sze-klmax)
do i=1,sze
out_val(i) = dcmplx(out_re(i),sign*sign2(i)*out_im(i))
enddo
else
call map_get_many(map2, hash_re(1:klmin-1), tmp_re(1:klmin-1), klmin-1)
call map_get_many(map2, hash_im(1:klmin-1), tmp_im(1:klmin-1), klmin-1)
call map_get_many(map, hash_re(klmin:klmax), tmp_re(klmin:klmax), klmax-klmin+1)
call map_get_many(map, hash_im(klmin:klmax), tmp_im(klmin:klmax), klmax-klmin+1)
call map_get_many(map2, hash_re(klmax+1:sze), tmp_re(klmax+1:sze), sze-klmax)
call map_get_many(map2, hash_im(klmax+1:sze), tmp_im(klmax+1:sze), sze-klmax)
! Conversion to double complex
do i=1,sze
out_val(i) = dcmplx(tmp_re(i),sign*sign2(i)*tmp_im(i))
enddo
endif
endif
end
subroutine get_mo_two_e_integrals_exch_ijji_complex(j,sze,out_val,map,map2)
use map_module
implicit none
BEGIN_DOC
! Returns multiple integrals <ij|ji>
! i*(1)j*(2) 1/r12 j(1)i(2) :: out_val(i)
! for j fixed.
! always real, always in map2
END_DOC
integer, intent(in) :: j, sze
double precision, intent(out) :: out_val(sze)
type(map_type), intent(inout) :: map,map2
integer :: i
integer(key_kind) :: hash(sze),hash_re(sze)
real(integral_kind) :: tmp_val(sze)
PROVIDE mo_two_e_integrals_in_map
do i=1,sze
!DIR$ FORCEINLINE
call two_e_integrals_index(i,j,j,i,hash(i))
!hash_re(i) = 2*hash(i) - 1
hash_re(i) = shiftl(hash(i),1) - 1
enddo
if (integral_kind == 8) then
call map_get_many(map2, hash_re, out_val, sze)
else
call map_get_many(map2, hash_re, tmp_val, sze)
! Conversion to double precision
do i=1,sze
out_val(i) = dble(tmp_val(i))
enddo
endif
end