31 use iso_fortran_env,
only: error_unit
33 use phys_const_gbl,
only: pi, imu
34 use precisn_gbl,
only: wp
46 integer,
allocatable :: l(:, :)
47 integer,
allocatable :: m(:, :)
48 complex(wp),
allocatable :: k(:, :)
49 integer,
allocatable :: idx(:, :)
50 complex(wp),
allocatable :: values(:, :)
91 integer,
intent(in) :: N, ne
92 real(wp),
intent(in) :: a, r0, c
94 if (
allocated(this % data))
deallocate(this % data)
96 allocate (this % data(n, ne))
112 logical function get_nested_cgreen_integ_cache_t (this, a, r0, c, N, sa, sb, m, l, k, val)
result (status)
116 real(wp),
intent(in) :: a, r0, c
117 integer,
intent(in) :: n, sa, sb, m(:), l(:)
118 complex(wp),
intent(in) :: k(:)
119 complex(wp),
intent(inout) :: val
121 integer :: i, im, il, ik
124 if (
allocated(this % data))
then
125 if (this % a == a .and. this % r0 == r0 .and. this % c == c .and.
size(this % data) >= n)
then
126 if (
allocated(this % data(n, this % ie) % values))
then
127 im =
find_column(this % data(n, this % ie) % m, m);
if (im == 0)
return
128 il =
find_column(this % data(n, this % ie) % l, l);
if (il == 0)
return
129 ik =
find_column(this % data(n, this % ie) % k, k);
if (ik == 0)
return
130 do i = 1,
size(this % data(n, this % ie) % idx, 2)
131 if (all(this % data(n, this % ie) % idx(:, i) == [sa, sb, im, il, ik]))
then
132 val = this % data(n, this % ie) % values(1, i)
150 subroutine set_nested_cgreen_integ_cache_t (this, a, r0, c, N, sa, sb, m, l, k, val)
154 real(wp),
intent(in) :: a, r0, c
155 integer,
intent(in) :: N, sa, sb, m(:), l(:)
156 complex(wp),
intent(in) :: k(:)
157 complex(wp),
intent(in) :: val
159 integer :: im, il, ik, ii
160 complex(wp) :: orig_val
162 if (this % get(a, r0, c, n, sa, sb, m, l, k, orig_val))
then
163 write (error_unit,
'(a)')
'Error: Overwriting existing integral cache entry'
167 if (this % a /= a .or. this % r0 /= r0 .or. this % c /= c)
then
168 write(error_unit,
'(a)')
'Error: Inserting value into cache for incompatible setup'
172 im =
find_column(this % data(n, this % ie) % m, m);
if (im == 0) im =
append_column(this % data(n, this % ie) % m, m)
173 il =
find_column(this % data(n, this % ie) % l, l);
if (il == 0) il =
append_column(this % data(n, this % ie) % l, l)
174 ik =
find_column(this % data(n, this % ie) % k, k);
if (ik == 0) ik =
append_column(this % data(n, this % ie) % k, k)
176 ii =
append_column(this % data(n, this % ie) % idx, [sa, sb, im, il, ik])
177 ii =
append_column(this % data(n, this % ie) % values, [val])
214 integer,
intent(in) :: n, m(0:n-1), s(0:2*n-1)
215 real(wp),
intent(in) :: z, a, c
216 complex(wp),
intent(in) :: k(0:2*n-1)
220 complex(wp) :: i(0:n*(npp+1)), f(0:n*(npp+1)-1), fg(0:n*(npp+1)-1), g(0:(n+1)*(npp+1)-1), j(0:n*(npp+1)-1)
221 complex(wp) :: t(0:npp, 0:n*(npp + 1)-1)
223 real(wp) :: b(0:n*(npp+1)-1, 0:n*(npp+1))
226 integer :: o, p, q, lvl
249 do p = lbound(b, 1), ubound(b, 1)
252 b(p, q) = b(p - 1, q - 1) + b(p - 1, q)
276 do p = 1, (n - lvl)*(npp + 1) - 1
277 f(p) = (m(lvl) + 1 - p) * f(p - 1) / a
283 do p = 0, (n - lvl)*(npp + 1) - 1
286 fg(p) = fg(p) + b(p,q) * f(p - q) * i(q)
296 u = u + s(2*lvl+1)*k(2*lvl+1) + s(2*lvl+0)*k(2*lvl+0) + imu*c
297 v = v + z*s(2*lvl+1)/abs(k(2*lvl+1)) + z*s(2*lvl+0)/abs(k(2*lvl+0))
299 g(0) = imu*a / (u*a + v)
300 g(1) = imu*v / ((u*a + v)*(u*a + v))
302 do p = 2, (n - lvl + 1)*(npp + 1) - 1
303 g(p) = g(p - 1) * (-p) * u / (u*a + v)
309 do p = 0, (n - lvl)*(npp + 1) - 1
314 do p = 0, (n - lvl)*(npp + 1) - o - 1
317 t(o, p) = t(o, p) + b(p + 1, q) * g(p + 1 - q) * t(o - 1, q)
324 do p = 0, (n - lvl - 1)*(npp + 1)
327 j(p) = j(p) + t(o, p)
333 do p = 0, (n - lvl - 1)*(npp + 1)
336 i(p) = i(p) + b(p, q) * g(p - q) * j(q)
374 integer,
intent(in) :: n, m(1:n), s(1:2*n), l(1:2*n)
375 real(wp),
intent(in) :: z, a, c
376 complex(wp),
intent(in) :: k(1:2*n)
378 integer :: nn(2*n), ms(n), p
379 complex(wp) :: an(2*n), bn(2*n), factor(2*n)
382 real(wp) :: total_phase, total_exponent, kr, ki
383 complex(wp) :: integ, err
393 an(p) = 1 + l(p) - z*s(p)*imu/k(p)
394 bn(p) = -l(p) - z*s(p)*imu/k(p)
398 do while (.not. at_end)
402 ms(p) = m(p) - nn(2*p-1) - nn(2*p-0)
410 integ = integ * factor(p)
424 factor(p) = factor(p) * (an(p) + nn(p) - 1) * (bn(p) + nn(p) - 1) / (2 * imu * s(p) * nn(p) * k(p))
440 total_phase = total_phase + s(p)*(kr*a + z*log(2*kr*a)/kr - pi*l(p)/2 +
cphase(z, l(p), kr))
443 total_exponent = total_exponent + s(p)*(-ki*a + z*log(2*ki*a)/ki)
448 val = val * cmplx(cos(total_phase), sin(total_phase), wp) * exp(total_exponent - n*c*a)
487 use ieee_arithmetic,
only: ieee_value, ieee_quiet_nan
488 use mpi_gbl,
only: mpi_xermsg
494 integer,
intent(in) :: n, sa, sb, m(:), l(:)
495 real(wp),
intent(in) :: z, a, c, r0
496 complex(wp),
intent(in) :: k(:)
499 integer :: order(n), mp(n), lp(2*n), sp(2*n), p, signs
501 complex(wp) :: kp(2*n), err, integ, ix, ia
503 character(len=100) :: msg
513 if (a < r0 .and. n == 1)
then
517 if (abs(ix) > 1e-10 .and. abs(ia - ix) >
coultol * abs(ix))
then
528 if (abs(ix) > 1e-10 .and. abs(ia - ix) > abs(ix))
then
532 write (*,
'(5x,A,3(I0,1x))', advance =
'no')
'Warning: Giving up Coul-Green integ '
533 write (*,
'(3(A,I0,SP))', advance =
'no')
'm = ', m,
', sa = ', sa,
', sb = ', sb
534 write (*,
'(A,*(I0,","))', advance =
'no')
', l = ', l
535 write (*,
'(A,SP,*(F0.4,","))', advance =
'no')
' E = ', real(k**2/2, wp)
536 write (*,
'(SP,2(A,2E10.4),A)')
' Ix = ', ix,
'i, Ia = ', ia,
'i'
555 do signs = 0, 2**(n - 1) - 1
582 if (order(p) > 1) sp(2*p - 1) = merge(merge(-1, +1, btest(signs, order(p) - 2)), +1, acc(order(p) - 1))
583 if (order(p) < n) sp(2*p - 0) = merge(merge(-1, +1, btest(signs, order(p) - 1)), +1, acc(order(p) + 1))
585 acc(order(p)) = .true.
587 kp(2*p - 1) = k(order(p) - 0)
588 kp(2*p - 0) = k(order(p) + 1)
590 lp(2*p - 1) = l(order(p) - 0)
591 lp(2*p - 0) = l(order(p) + 1)
607 val = val * imu / k(p)
614 call nested_cgreen_correct_romberg(z, a, b, c, n, sa, sb, m, l, k, val)
616 call nested_cgreen_correct_levin(z, a, b, c, n, sa, sb, m, l, k, val)
618 write (msg,
'(a,i0)')
'Unknown numerical integration algorithm ',
num_integ_algo
619 call mpi_xermsg(
'multidip_integ',
'nested_cgreen_integ', trim(msg), 1, 1)
Special integrals needed by MULTIDIP.
logical function get_nested_cgreen_integ_cache_t(this, a, r0, c, N, sa, sb, m, l, k, val)
Get integral from cache.
subroutine init_nested_cgreen_integ_cache_t(this, N, ne, a, r0, c)
Initialize integral cache.
subroutine set_nested_cgreen_integ_cache_t(this, a, r0, c, N, sa, sb, m, l, k, val)
Add integral to cache.
complex(wp) function nested_cgreen_integ(Z, a, r0, c, N, sa, sb, m, l, k)
Multi-dimensional integral of Coulomb-Hankel and Coulomb-Green functions and powers.
complex(wp) function nested_exp_integ(Z, a, c, N, m, s, k)
Multi-dimensional triangular integral of exponentials and powers.
complex(wp) function nested_coul_integ(Z, a, c, N, m, s, l, k)
Multi-dimensional triangular integral of Coulomb-Hankel functions and powers.
type(nested_cgreen_integ_cache_t) nested_cgreen_integ_cache
Levin quadrature for numerical integration.
subroutine nested_cgreen_correct_levin(Z, a, b, c, N, sa, sb, m, l, k, v)
Numerically correct asymptotic approximation of the Coulomb-Green integral (Levin integration)
Hard-coded parameters of MULTIDIP.
integer, parameter ntermsppt
Number of terms in expansion of the exponential integral.
integer num_integ_algo
Numerical integration mode (1 = Romberg, 2 = Levin)
logical cache_integrals
Cache Coulomb-Green integrals in memory (but disables some threading)
logical coulomb_check
Skip integrals that cannot be asymptotically approximated well.
real(wp) coultol
Coulomb matching relative tolerance (decides whether to use asym. forms)
logical print_warnings
Print warnings about non-converged integrals.
integer, parameter ntermsasy
Number of terms in expansion of the Coulomb-Hankel functions.
Romberg quadrature for numerical integration.
complex(wp) function nested_cgreen_eval(Z, c, N, sa, sb, m, l, k, rs, asy)
Evaluate the Coulomb-Green's integrand.
subroutine nested_cgreen_correct_romberg(Z, a, b, c, N, sa, sb, m, l, k, v)
Numerically correct asymptotic approximation of the Coulomb-Green integral (Romberg integration)
Special functions and objects used by MULTIDIP.
subroutine kahan_add(X, dX, err)
Compensated summation.
complex(wp) function coulh(Z, s, l, Ek, r)
Coulomb-Hankel function.
complex(wp) function coulh_asy(Z, s, l, Ek, r)
Coulomb-Hankel function (asymptotic form)
real(wp) function cphase(Z, l, k)
Coulomb phase.
logical function next_permutation(p)
Construct or advance permutation.