39 use precisn_gbl,
only: wp
69 subroutine nested_cgreen_correct_levin (Z, a, b, c, N, sa, sb, m, l, k, v)
71 integer,
intent(in) :: N, sa, sb, m(:), l(:)
72 real(wp),
intent(in) :: Z, a, b, c
73 complex(wp),
intent(in) :: k(:)
74 complex(wp),
intent(inout) :: v
77 v = v +
levin_adapt(z, a, b, c, m(1), sa, sb, l(1), l(2), k(1), k(2))
133 complex(wp) function levin_adapt (Z, ra, rb, c, m, s1, s2, l1, l2, k1, k2)
result (integ)
137 real(wp),
intent(in) :: z, ra, rb, c
138 complex(wp),
intent(in) :: k1, k2
139 integer,
intent(in) :: m, s1, s2, l1, l2
144 logical :: converged(max_intervals)
145 complex(wp) :: estimates(max_intervals)
146 complex(wp) :: hl_buffer(2, 2, max_intervals + 1)
149 converged(1) = .false.
155 call levin_prepare(z, ra, rb, s1, s2, l1, l2, k1, k2, depth, converged, hl_buffer)
158 call levin_improve(z, ra, rb, c, m, l1, l2, k1, k2, 0, 1, depth, converged, hl_buffer, estimates)
161 if (.not. estimates(1) == estimates(1))
then
162 print
'(a)',
'WARNING: NaN encountered during Levin quadrature'
167 if (converged(1))
exit
173 print
'(A,I0,A)',
'WARNING: Adaptive Levin integration did not converge in ',
max_levin_level,
' subdivisions'
204 subroutine levin_prepare (Z, ra, rb, s1, s2, l1, l2, k1, k2, depth, converged, Hl_buffer)
206 integer,
intent(in) :: s1, s2, l1, l2, depth
207 real(wp),
intent(in) :: Z, ra, rb
208 complex(wp),
intent(in) :: k1, k2
209 complex(wp),
intent(inout) :: Hl_buffer(2, 2, *)
210 logical,
intent(inout) :: converged(:)
213 integer :: num_intervals, first_interval_idx, interval_idx, parent_interval_idx, evaluation_point_idx, storage_point_idx
215 num_intervals = 2**depth
216 first_interval_idx = 2**depth
220 call levin_eval(z, ra, s1, s2, l1, l2, k1, k2, hl_buffer(:, :, 2))
221 call levin_eval(z, rb, s1, s2, l1, l2, k1, k2, hl_buffer(:, :, 1))
226 do interval_idx = first_interval_idx, first_interval_idx + num_intervals - 1, 2
231 parent_interval_idx = interval_idx / 2
234 if (converged(parent_interval_idx))
then
235 converged(interval_idx) = .true.
236 converged(interval_idx + 1) = .true.
243 converged(interval_idx) = .false.
244 converged(interval_idx + 1) = .false.
247 evaluation_point_idx = interval_idx + 1
248 storage_point_idx = (evaluation_point_idx + 3)/2
251 r = ra + (evaluation_point_idx - first_interval_idx) * (rb - ra) / num_intervals
254 call levin_eval(z, r, s1, s2, l1, l2, k1, k2, hl_buffer(:, :, storage_point_idx))
289 real(wp),
intent(in) :: Z, r
290 integer,
intent(in) :: s1, s2, l1, l2
291 complex(wp),
intent(in) :: k1, k2
292 complex(wp),
intent(inout) :: Hl(2, 2)
296 ek1 = real(k1**2, wp)/2
297 ek2 = real(k2**2, wp)/2
299 hl(1, 1) =
coulh(z, s1, l1, ek1, r)
300 hl(2, 1) =
coulh(z, s1, l1 + 1, ek1, r)
301 hl(1, 2) =
coulh(z, s2, l2, ek2, r)
302 hl(2, 2) =
coulh(z, s2, l2 + 1, ek2, r)
336 recursive subroutine levin_improve (Z, ra, rb, c, m, l1, l2, k1, k2, depth, interval_idx, tgt_depth, converged, Hl, estimates)
338 real(wp),
intent(in) :: z, ra, rb, c
339 complex(wp),
intent(in) :: k1, k2
340 integer,
intent(in) :: m, l1, l2, depth, interval_idx, tgt_depth
341 complex(wp),
intent(in) :: hl(2, 2, *)
342 logical,
intent(inout) :: converged(:)
343 complex(wp),
intent(inout) :: estimates(:)
345 integer :: num_local_intervals, first_interval_idx, max_global_point_idx, left_point_global_idx, right_point_global_idx
346 integer :: left_point_local_idx, right_point_local_idx, left_point_unique_idx, right_point_unique_idx
347 integer :: left_point_storage_idx, right_point_storage_idx, left_subinterval_idx, right_subinterval_idx
348 real(wp) :: a, b, epsrel, epsabs, delta, reference
350 complex(wp) :: best_estimate,improved_estimate
353 if (depth == tgt_depth)
then
355 num_local_intervals = 2**depth
356 first_interval_idx = 2**depth
357 max_global_point_idx = 2**(depth + 1)
359 left_point_global_idx = interval_idx;
360 right_point_global_idx = left_point_global_idx + 1
362 left_point_local_idx = interval_idx - first_interval_idx
363 right_point_local_idx = left_point_local_idx + 1
365 left_point_unique_idx = shiftr(left_point_global_idx, trailz(left_point_global_idx))
366 right_point_unique_idx = shiftr(mod(right_point_global_idx, max_global_point_idx), trailz(right_point_global_idx))
368 left_point_storage_idx = (left_point_unique_idx + 3)/2
369 right_point_storage_idx = merge(1, (right_point_unique_idx + 3)/2, right_point_unique_idx == 0)
371 a = ra + left_point_local_idx * (rb - ra) / num_local_intervals
372 b = ra + right_point_local_idx * (rb - ra) / num_local_intervals
374 estimates(interval_idx) =
levin_integrate(z, a, b, c, m, l1, l2, k1, k2, &
375 hl(:, :, left_point_storage_idx), &
376 hl(:, :, right_point_storage_idx))
383 left_subinterval_idx = 2*interval_idx;
384 right_subinterval_idx = 2*interval_idx + 1;
387 if (.not. converged(left_subinterval_idx))
then
389 depth + 1, left_subinterval_idx, tgt_depth, converged, hl, estimates)
391 if (.not. converged(right_subinterval_idx))
then
393 depth + 1, right_subinterval_idx, tgt_depth, converged, hl, estimates)
397 best_estimate = estimates(interval_idx)
398 improved_estimate = estimates(left_subinterval_idx) + estimates(right_subinterval_idx)
400 epsabs = epsrel * abs(estimates(1))
401 delta = abs(best_estimate - improved_estimate)
402 reference = 0.5 * (abs(best_estimate) + abs(improved_estimate))
403 if (delta < epsabs * reference .or. delta < epsabs)
then
404 converged(interval_idx) = .true.
405 converged(left_subinterval_idx) = .true.
406 converged(right_subinterval_idx) = .true.
410 estimates(interval_idx) = improved_estimate
442 complex(wp) function levin_integrate (Z, ra, rb, c, m, l1, l2, k1, k2, Hla, Hlb)
result (integ)
444 use mpi_gbl,
only: mpi_xermsg
446 real(wp),
intent(in) :: z, ra, rb, c
447 complex(wp),
intent(in) :: k1, k2
448 integer,
intent(in) :: m, l1, l2
449 complex(wp),
intent(in) :: hla(2, 2), hlb(2, 2)
451 if (aimag(k1) == 0 .and. aimag(k2) == 0)
then
453 integ =
levin_integrate_4x4(z, ra, rb, c, m, l1, l2, real(k1, wp), real(k2, wp), hla, hlb)
454 else if (aimag(k1) == 0 .and. aimag(k2) /= 0)
then
456 integ =
levin_integrate_2x2(z, ra, rb, c, m, l2, l1, aimag(k2), real(k1, wp), hla(:, 1), hlb(:, 1))
457 else if (aimag(k1) /= 0 .and. aimag(k2) == 0)
then
459 integ =
levin_integrate_2x2(z, ra, rb, c, m, l1, l2, aimag(k1), real(k2, wp), hla(:, 2), hlb(:, 2))
461 call mpi_xermsg(
'multidip_levin',
'levin_integrate',
'Levin integrator cannot integrate closed-closed integrals.', 1, 1)
524 complex(wp) function levin_integrate_2x2 (Z, ra, rb, c, m, lc, lo, kc, ko, wa, wb)
result (integ)
526 use blas_lapack_gbl,
only: blasint
527 use mpi_gbl,
only: mpi_xermsg
530 use phys_const_gbl,
only: pi
532 real(wp),
intent(in) :: z, ra, rb, c, kc, ko
533 integer,
intent(in) :: m, lc, lo
534 complex(wp),
intent(in) :: wa(2), wb(2)
536 integer,
parameter :: levin_dim = 2
537 integer,
parameter :: mat_dim = levin_dim * (
cheb_order + 1)
539 integer :: ipoly, inode, a, b, i, j, row, col, sgn, ifun, flips
541 real(wp) :: x, r, rl, elem, cx
545 real(wp) :: aa(levin_dim, levin_dim)
546 real(wp) :: ab(levin_dim, levin_dim)
547 real(wp) :: mat(mat_dim, mat_dim)
548 real(wp) :: coef(mat_dim)
549 real(wp) :: pa(levin_dim), pb(levin_dim)
551 complex(wp) :: hlna, hlnb, hlpa, hlpb, wl
552 complex(wp) :: contrib_a, contrib_b, delta
554 integer(blasint) :: n, pivots(mat_dim), info
558 call mpi_xermsg(
'multidip_levin',
'levin_integrate_2x2', &
559 'Levin integration not implemented for non-positive intervals', 1, 1)
563 rl = sqrt(ko*ko + z*z/((lo + 1)*(lo + 1)))
565 aa(1, 1) = + lo + 1; aa(1, 2) = 0
566 aa(2, 1) = 0; aa(2, 2) = - lo - 1
568 ab(1, 1) = -z/(lo + 1); ab(1, 2) = -rl
569 ab(2, 1) = +rl; ab(2, 2) = +z/(lo + 1)
578 cheb_value(inode, 0) = 1; cheb_deriv(inode, 0) = 0
579 cheb_value(inode, 1) = x; cheb_deriv(inode, 1) = 1
582 cheb_value(inode, ipoly + 1) = 2*x*cheb_value(inode, ipoly) - cheb_value(inode, ipoly - 1)
583 cheb_deriv(inode, ipoly + 1) = 2*(ipoly + 1)*cheb_value(inode, ipoly) &
584 + (ipoly + 1)*cheb_deriv(inode, ipoly - 1) / max(1, ipoly - 1)
597 r = ra + (x + 1) / 2 * (rb - ra)
598 elem = aa(b, a)/r + ab(b, a)
599 mat(row, col) = elem * cheb_value(i, j)
601 mat(row, col) = mat(row, col) + 2/(rb - ra) * cheb_deriv(i, j)
613 r = ra + (x + 1) * (rb - ra) / 2
615 wl = real(
coulh(z, 0, lc, -kc*kc/2, r), wp)
616 coef(row) = r**m * exp(-c*r) * wl
625 call blas_dgetrf(n, n, mat, n, pivots, info)
627 call mpi_xermsg(
'multidip_levin',
'levin_integrate_2x2', &
628 'LU decomposition in Levin integration failed', int(info), 1)
630 call blas_dgetrs(
'N', n, 1_blasint, mat, n, pivots, coef, n, info)
632 call mpi_xermsg(
'multidip_levin',
'levin_integrate_2x2', &
633 'LU backsubstitution in Levin integration failed', int(info), 1)
643 sgn = merge(+1, -1, mod(i, 2) == 0)
644 pa(a) = pa(a) + sgn*cx
651 do ifun = 1, levin_dim
652 contrib_a = wa(ifun) * pa(ifun)
653 contrib_b = wb(ifun) * pb(ifun)
654 delta = contrib_b - contrib_a
655 integ = integ + delta
720 complex(wp) function levin_integrate_4x4 (Z, ra, rb, c, m, l1, l2, k1, k2, Hla, Hlb)
result (integ)
722 use blas_lapack_gbl,
only: blasint
723 use mpi_gbl,
only: mpi_xermsg
726 use phys_const_gbl,
only: pi
728 real(wp),
intent(in) :: z, ra, rb, c, k1, k2
729 integer,
intent(in) :: m, l1, l2
730 complex(wp),
intent(in) :: hla(2, 2), hlb(2, 2)
732 integer,
parameter :: levin_dim = 4
733 integer,
parameter :: mat_dim = levin_dim * (
cheb_order + 1)
735 integer :: ipoly, inode, a, b, i, j, row, col, sgn, ifun, flips
737 real(wp) :: x, r, r1, r2, elem, cx
741 real(wp) :: aa(levin_dim, levin_dim)
742 real(wp) :: ab(levin_dim, levin_dim)
743 real(wp) :: mat(mat_dim, mat_dim)
744 real(wp) :: coef(mat_dim)
745 real(wp) :: pa(levin_dim), pb(levin_dim)
747 complex(wp) :: hln1a, hln2a, hln1b, hln2b, hlp1a, hlp2a, hlp1b, hlp2b, wa(levin_dim), wb(levin_dim)
748 complex(wp) :: contrib_a, contrib_b, delta
750 integer(blasint) :: n, pivots(mat_dim), info
754 call mpi_xermsg(
'multidip_levin',
'levin_integrate_4x4', &
755 'Levin integration not implemented for non-positive intervals', 1, 1)
762 r1 = sqrt(k1*k1 + z/((l1 + 1)*(l1 + 1)))
763 r2 = sqrt(k2*k2 + z/((l2 + 1)*(l2 + 1)))
765 aa(1, 1) = + l1 + l2 + 2
768 aa(4, 4) = - l1 - l2 - 2
770 ab(1, 1) = - z/(l1 + 1) - z/(l2 + 1)
771 ab(2, 2) = - z/(l1 + 1) + z/(l2 + 1)
772 ab(3, 3) = + z/(l1 + 1) - z/(l2 + 1)
773 ab(4, 4) = + z/(l1 + 1) + z/(l2 + 1)
775 ab(1, 2) = -r2; ab(1, 3) = -r1
776 ab(2, 1) = +r2; ab(2, 4) = -r1
777 ab(3, 1) = +r1; ab(3, 4) = -r2
778 ab(4, 2) = +r1; ab(4, 3) = +r2
787 cheb_value(inode, 0) = 1; cheb_deriv(inode, 0) = 0
788 cheb_value(inode, 1) = x; cheb_deriv(inode, 1) = 1
791 cheb_value(inode, ipoly + 1) = 2*x*cheb_value(inode, ipoly) - cheb_value(inode, ipoly - 1)
792 cheb_deriv(inode, ipoly + 1) = 2*(ipoly + 1)*cheb_value(inode, ipoly) &
793 + (ipoly + 1)*cheb_deriv(inode, ipoly - 1) / max(1, ipoly - 1)
806 r = ra + (x + 1) / 2 * (rb - ra)
807 elem = aa(b, a)/r + ab(b, a)
808 mat(row, col) = elem * cheb_value(i, j)
810 mat(row, col) = mat(row, col) + 2/(rb - ra) * cheb_deriv(i, j)
823 r = ra + (x + 1) * (rb - ra) / 2
825 coef(row) = r**m * exp(-c*r)
834 call blas_dgetrf(n, n, mat, n, pivots, info)
836 call mpi_xermsg(
'multidip_levin',
'levin_integrate_4x4', &
837 'LU decomposition in Levin integration failed', int(info), 1)
839 call blas_dgetrs(
'N', n, 1_blasint, mat, n, pivots, coef, n, info)
841 call mpi_xermsg(
'multidip_levin',
'levin_integrate_4x4', &
842 'LU backsubstitution in Levin integration failed', int(info), 1)
845 hln1a = hla(1, 1); hlp1a = hla(2, 1)
846 hln2a = hla(1, 2); hlp2a = hla(2, 2)
847 hln1b = hlb(1, 1); hlp1b = hlb(2, 1)
848 hln2b = hlb(1, 2); hlp2b = hlb(2, 2)
850 wa = [ hln1a * hln2a, hln1a * hlp2a, hlp1a * hln2a, hlp1a * hlp2a ]
851 wb = [ hln1b * hln2b, hln1b * hlp2b, hlp1b * hln2b, hlp1b * hlp2b ]
860 sgn = merge(+1, -1, mod(i, 2) == 0)
861 pa(a) = pa(a) + sgn*cx
868 do ifun = 1, levin_dim
869 contrib_a = wa(ifun) * pa(ifun)
870 contrib_b = wb(ifun) * pb(ifun)
871 delta = contrib_b - contrib_a
872 integ = integ + delta
Levin quadrature for numerical integration.
complex(wp) function levin_integrate_4x4(Z, ra, rb, c, m, l1, l2, k1, k2, Hla, Hlb)
Fixed-order Levin integration (dim 4)
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)
complex(wp) function levin_integrate_2x2(Z, ra, rb, c, m, lc, lo, kc, ko, wa, wb)
Fixed-order Levin integration (dim 2)
subroutine levin_prepare(Z, ra, rb, s1, s2, l1, l2, k1, k2, depth, converged, Hl_buffer)
Precalculate Coulomb-Hankel functions for subsequent Levin integration.
complex(wp) function levin_adapt(Z, ra, rb, c, m, s1, s2, l1, l2, k1, k2)
One-dimensional adaptive Levin integration.
subroutine levin_eval(Z, r, s1, s2, l1, l2, k1, k2, Hl)
Evaluate a pair of Coulomb-Hankel functions in given point.
recursive subroutine levin_improve(Z, ra, rb, c, m, l1, l2, k1, k2, depth, interval_idx, tgt_depth, converged, Hl, estimates)
Perform one subdivision iteration of adaptive Levin integration and update estimates.
complex(wp) function levin_integrate(Z, ra, rb, c, m, l1, l2, k1, k2, Hla, Hlb)
Fixed-order Levin integration.
Hard-coded parameters of MULTIDIP.
real(wp), parameter rhalf
integer, parameter max_levin_level
Maximal nesting level for Levin integration.
integer, parameter cheb_order
Order of Chebyshev interpolation used in Levin quadrature.
Special functions and objects used by MULTIDIP.
complex(wp) function coulh(Z, s, l, Ek, r)
Coulomb-Hankel function.