135 complex(wp) function levin_adapt (Z, ra, rb, c, m, s1, s2, l1, l2, k1, k2)
result (integ)
139 real(wp),
intent(in) :: z, ra, rb, c
140 complex(wp),
intent(in) :: k1, k2
141 integer,
intent(in) :: m, s1, s2, l1, l2
146 logical :: converged(max_intervals)
147 complex(wp) :: estimates(max_intervals)
148 complex(wp) :: hl_buffer(2, 2, max_intervals + 1)
151 converged(1) = .false.
157 call levin_prepare(z, ra, rb, s1, s2, l1, l2, k1, k2, depth, converged, hl_buffer)
160 call levin_improve(z, ra, rb, c, m, l1, l2, k1, k2, 0, 1, depth, converged, hl_buffer, estimates)
163 if (.not. estimates(1) == estimates(1))
then
164 print
'(a)',
'WARNING: NaN encountered during Levin quadrature'
169 if (converged(1))
exit
175 print
'(A,I0,A)',
'WARNING: Adaptive Levin integration did not converge in ',
max_levin_level,
' subdivisions'
206 subroutine levin_prepare (Z, ra, rb, s1, s2, l1, l2, k1, k2, depth, converged, Hl_buffer)
208 integer,
intent(in) :: s1, s2, l1, l2, depth
209 real(wp),
intent(in) :: Z, ra, rb
210 complex(wp),
intent(in) :: k1, k2
211 complex(wp),
intent(inout) :: Hl_buffer(2, 2, *)
212 logical,
intent(inout) :: converged(:)
215 integer :: num_intervals, first_interval_idx, interval_idx, parent_interval_idx, evaluation_point_idx, storage_point_idx
217 num_intervals = 2**depth
218 first_interval_idx = 2**depth
222 call levin_eval(z, ra, s1, s2, l1, l2, k1, k2, hl_buffer(:, :, 2))
223 call levin_eval(z, rb, s1, s2, l1, l2, k1, k2, hl_buffer(:, :, 1))
228 do interval_idx = first_interval_idx, first_interval_idx + num_intervals - 1, 2
233 parent_interval_idx = interval_idx / 2
236 if (converged(parent_interval_idx))
then
237 converged(interval_idx) = .true.
238 converged(interval_idx + 1) = .true.
245 converged(interval_idx) = .false.
246 converged(interval_idx + 1) = .false.
249 evaluation_point_idx = interval_idx + 1
250 storage_point_idx = (evaluation_point_idx + 3)/2
253 r = ra + (evaluation_point_idx - first_interval_idx) * (rb - ra) / num_intervals
256 call levin_eval(z, r, s1, s2, l1, l2, k1, k2, hl_buffer(:, :, storage_point_idx))
292 real(wp),
intent(in) :: Z, r
293 integer,
intent(in) :: s1, s2, l1, l2
294 complex(wp),
intent(in) :: k1, k2
295 complex(wp),
intent(inout) :: Hl(2, 2)
299 ek1 = real(k1**2, wp)/2
300 ek2 = real(k2**2, wp)/2
303 hl(1, 1) = aimag(coulh(z, +1, l1, ek1, r))
304 hl(2, 1) = aimag(coulh(z, +1, l1 + 1, ek1, r))
306 hl(1, 1) = coulh(z, s1, l1, ek1, r)
307 hl(2, 1) = coulh(z, s1, l1 + 1, ek1, r)
311 hl(1, 2) = aimag(coulh(z, +1, l2, ek2, r))
312 hl(2, 2) = aimag(coulh(z, +1, l2 + 1, ek2, r))
314 hl(1, 2) = coulh(z, s2, l2, ek2, r)
315 hl(2, 2) = coulh(z, s2, l2 + 1, ek2, r)
350 recursive subroutine levin_improve (Z, ra, rb, c, m, l1, l2, k1, k2, depth, interval_idx, tgt_depth, converged, Hl, estimates)
352 real(wp),
intent(in) :: z, ra, rb, c
353 complex(wp),
intent(in) :: k1, k2
354 integer,
intent(in) :: m, l1, l2, depth, interval_idx, tgt_depth
355 complex(wp),
intent(in) :: hl(2, 2, *)
356 logical,
intent(inout) :: converged(:)
357 complex(wp),
intent(inout) :: estimates(:)
359 integer :: num_local_intervals, first_interval_idx, max_global_point_idx, left_point_global_idx, right_point_global_idx
360 integer :: left_point_local_idx, right_point_local_idx, left_point_unique_idx, right_point_unique_idx
361 integer :: left_point_storage_idx, right_point_storage_idx, left_subinterval_idx, right_subinterval_idx
362 real(wp) :: a, b, epsrel, epsabs, delta, reference
364 complex(wp) :: best_estimate,improved_estimate
367 if (depth == tgt_depth)
then
369 num_local_intervals = 2**depth
370 first_interval_idx = 2**depth
371 max_global_point_idx = 2**(depth + 1)
373 left_point_global_idx = interval_idx;
374 right_point_global_idx = left_point_global_idx + 1
376 left_point_local_idx = interval_idx - first_interval_idx
377 right_point_local_idx = left_point_local_idx + 1
379 left_point_unique_idx = shiftr(left_point_global_idx, trailz(left_point_global_idx))
380 right_point_unique_idx = shiftr(mod(right_point_global_idx, max_global_point_idx), trailz(right_point_global_idx))
382 left_point_storage_idx = (left_point_unique_idx + 3)/2
383 right_point_storage_idx = merge(1, (right_point_unique_idx + 3)/2, right_point_unique_idx == 0)
385 a = ra + left_point_local_idx * (rb - ra) / num_local_intervals
386 b = ra + right_point_local_idx * (rb - ra) / num_local_intervals
388 estimates(interval_idx) =
levin_integrate(z, a, b, c, m, l1, l2, k1, k2, &
389 hl(:, :, left_point_storage_idx), &
390 hl(:, :, right_point_storage_idx))
397 left_subinterval_idx = 2*interval_idx;
398 right_subinterval_idx = 2*interval_idx + 1;
401 if (.not. converged(left_subinterval_idx))
then
403 depth + 1, left_subinterval_idx, tgt_depth, converged, hl, estimates)
405 if (.not. converged(right_subinterval_idx))
then
407 depth + 1, right_subinterval_idx, tgt_depth, converged, hl, estimates)
411 best_estimate = estimates(interval_idx)
412 improved_estimate = estimates(left_subinterval_idx) + estimates(right_subinterval_idx)
414 epsabs = epsrel * abs(estimates(1))
415 delta = abs(best_estimate - improved_estimate)
416 reference = 0.5 * (abs(best_estimate) + abs(improved_estimate))
417 if (delta < epsabs * reference .or. delta < epsabs)
then
418 converged(interval_idx) = .true.
419 converged(left_subinterval_idx) = .true.
420 converged(right_subinterval_idx) = .true.
424 estimates(interval_idx) = improved_estimate
456 complex(wp) function levin_integrate (Z, ra, rb, c, m, l1, l2, k1, k2, Hla, Hlb)
result (integ)
458 use mpi_gbl,
only: mpi_xermsg
460 real(wp),
intent(in) :: z, ra, rb, c
461 complex(wp),
intent(in) :: k1, k2
462 integer,
intent(in) :: m, l1, l2
463 complex(wp),
intent(in) :: hla(2, 2), hlb(2, 2)
465 if (aimag(k1) == 0 .and. aimag(k2) == 0)
then
467 integ =
levin_integrate_4x4(z, ra, rb, c, m, l1, l2, real(k1, wp), real(k2, wp), hla, hlb)
468 else if (aimag(k1) == 0 .and. aimag(k2) /= 0)
then
470 integ =
levin_integrate_2x2(z, ra, rb, c, m, l2, l1, aimag(k2), real(k1, wp), hla(:, 1), hlb(:, 1))
471 else if (aimag(k1) /= 0 .and. aimag(k2) == 0)
then
473 integ =
levin_integrate_2x2(z, ra, rb, c, m, l1, l2, aimag(k1), real(k2, wp), hla(:, 2), hlb(:, 2))
475 call mpi_xermsg(
'multidip_levin',
'levin_integrate',
'Levin integrator cannot integrate closed-closed integrals.', 1, 1)
538 complex(wp) function levin_integrate_2x2 (Z, ra, rb, c, m, lc, lo, kc, ko, wa, wb)
result (integ)
540 use blas_lapack_gbl,
only: blasint
541 use mpi_gbl,
only: mpi_xermsg
544 use phys_const_gbl,
only:
pi
546 real(wp),
intent(in) :: z, ra, rb, c, kc, ko
547 integer,
intent(in) :: m, lc, lo
548 complex(wp),
intent(in) :: wa(2), wb(2)
550 integer,
parameter :: levin_dim = 2
551 integer,
parameter :: mat_dim = levin_dim * (
cheb_order + 1)
553 integer :: ipoly, inode, a, b, i, j, row, col, sgn, ifun
555 real(wp) :: x, r, rl, wl, elem, cx
559 real(wp) :: aa(levin_dim, levin_dim)
560 real(wp) :: ab(levin_dim, levin_dim)
561 real(wp) :: mat(mat_dim, mat_dim)
562 real(wp) :: coef(mat_dim)
563 real(wp) :: pa(levin_dim), pb(levin_dim)
565 complex(wp) :: contrib_a, contrib_b, delta
567 integer(blasint) :: n, pivots(mat_dim), info
571 call mpi_xermsg(
'multidip_levin',
'levin_integrate_2x2', &
572 'Levin integration not implemented for non-positive intervals', 1, 1)
576 rl = sqrt(ko*ko + z*z/((lo + 1)*(lo + 1)))
578 aa(1, 1) = + lo + 1; aa(1, 2) = 0
579 aa(2, 1) = 0; aa(2, 2) = - lo - 1
581 ab(1, 1) = -z/(lo + 1); ab(1, 2) = -rl
582 ab(2, 1) = +rl; ab(2, 2) = +z/(lo + 1)
591 cheb_value(inode, 0) = 1; cheb_deriv(inode, 0) = 0
592 cheb_value(inode, 1) = x; cheb_deriv(inode, 1) = 1
595 cheb_value(inode, ipoly + 1) = 2*x*cheb_value(inode, ipoly) - cheb_value(inode, ipoly - 1)
596 cheb_deriv(inode, ipoly + 1) = 2*(ipoly + 1)*cheb_value(inode, ipoly) &
597 + (ipoly + 1)*cheb_deriv(inode, ipoly - 1) / max(1, ipoly - 1)
610 r = ra + (x + 1) / 2 * (rb - ra)
611 elem = aa(b, a)/r + ab(b, a)
612 mat(row, col) = elem * cheb_value(i, j)
614 mat(row, col) = mat(row, col) + 2/(rb - ra) * cheb_deriv(i, j)
626 r = ra + (x + 1) * (rb - ra) / 2
628 wl = real(coulh(z, 0, lc, -kc*kc/2, r), wp)
629 coef(row) = r**m * exp(-c*r) * wl
638 call blas_dgetrf(n, n, mat, n, pivots, info)
640 call mpi_xermsg(
'multidip_levin',
'levin_integrate_2x2', &
641 'LU decomposition in Levin integration failed', int(info), 1)
643 call blas_dgetrs(
'N', n, 1_blasint, mat, n, pivots, coef, n, info)
645 call mpi_xermsg(
'multidip_levin',
'levin_integrate_2x2', &
646 'LU backsubstitution in Levin integration failed', int(info), 1)
656 sgn = merge(+1, -1, mod(i, 2) == 0)
657 pa(a) = pa(a) + sgn*cx
664 do ifun = 1, levin_dim
665 contrib_a = wa(ifun) * pa(ifun)
666 contrib_b = wb(ifun) * pb(ifun)
667 delta = contrib_b - contrib_a
668 integ = integ + delta
733 complex(wp) function levin_integrate_4x4 (Z, ra, rb, c, m, l1, l2, k1, k2, Hla, Hlb)
result (integ)
735 use blas_lapack_gbl,
only: blasint
736 use mpi_gbl,
only: mpi_xermsg
739 use phys_const_gbl,
only:
pi
741 real(wp),
intent(in) :: z, ra, rb, c, k1, k2
742 integer,
intent(in) :: m, l1, l2
743 complex(wp),
intent(in) :: hla(2, 2), hlb(2, 2)
745 integer,
parameter :: levin_dim = 4
746 integer,
parameter :: mat_dim = levin_dim * (
cheb_order + 1)
748 integer :: ipoly, inode, a, b, i, j, row, col, sgn, ifun
750 real(wp) :: x, r, r1, r2, elem, cx
754 real(wp) :: aa(levin_dim, levin_dim)
755 real(wp) :: ab(levin_dim, levin_dim)
756 real(wp) :: mat(mat_dim, mat_dim)
757 real(wp) :: coef(mat_dim)
758 real(wp) :: pa(levin_dim), pb(levin_dim)
760 complex(wp) :: hln1a, hln2a, hln1b, hln2b, hlp1a, hlp2a, hlp1b, hlp2b, wa(levin_dim), wb(levin_dim)
761 complex(wp) :: contrib_a, contrib_b, delta
763 integer(blasint) :: n, pivots(mat_dim), info
767 call mpi_xermsg(
'multidip_levin',
'levin_integrate_4x4', &
768 'Levin integration not implemented for non-positive intervals', 1, 1)
775 r1 = sqrt(k1*k1 + z/((l1 + 1)*(l1 + 1)))
776 r2 = sqrt(k2*k2 + z/((l2 + 1)*(l2 + 1)))
778 aa(1, 1) = + l1 + l2 + 2
781 aa(4, 4) = - l1 - l2 - 2
783 ab(1, 1) = - z/(l1 + 1) - z/(l2 + 1)
784 ab(2, 2) = - z/(l1 + 1) + z/(l2 + 1)
785 ab(3, 3) = + z/(l1 + 1) - z/(l2 + 1)
786 ab(4, 4) = + z/(l1 + 1) + z/(l2 + 1)
788 ab(1, 2) = -r2; ab(1, 3) = -r1
789 ab(2, 1) = +r2; ab(2, 4) = -r1
790 ab(3, 1) = +r1; ab(3, 4) = -r2
791 ab(4, 2) = +r1; ab(4, 3) = +r2
800 cheb_value(inode, 0) = 1; cheb_deriv(inode, 0) = 0
801 cheb_value(inode, 1) = x; cheb_deriv(inode, 1) = 1
804 cheb_value(inode, ipoly + 1) = 2*x*cheb_value(inode, ipoly) - cheb_value(inode, ipoly - 1)
805 cheb_deriv(inode, ipoly + 1) = 2*(ipoly + 1)*cheb_value(inode, ipoly) &
806 + (ipoly + 1)*cheb_deriv(inode, ipoly - 1) / max(1, ipoly - 1)
819 r = ra + (x + 1) / 2 * (rb - ra)
820 elem = aa(b, a)/r + ab(b, a)
821 mat(row, col) = elem * cheb_value(i, j)
823 mat(row, col) = mat(row, col) + 2/(rb - ra) * cheb_deriv(i, j)
836 r = ra + (x + 1) * (rb - ra) / 2
838 coef(row) = r**m * exp(-c*r)
847 call blas_dgetrf(n, n, mat, n, pivots, info)
849 call mpi_xermsg(
'multidip_levin',
'levin_integrate_4x4', &
850 'LU decomposition in Levin integration failed', int(info), 1)
852 call blas_dgetrs(
'N', n, 1_blasint, mat, n, pivots, coef, n, info)
854 call mpi_xermsg(
'multidip_levin',
'levin_integrate_4x4', &
855 'LU backsubstitution in Levin integration failed', int(info), 1)
858 hln1a = hla(1, 1); hlp1a = hla(2, 1)
859 hln2a = hla(1, 2); hlp2a = hla(2, 2)
860 hln1b = hlb(1, 1); hlp1b = hlb(2, 1)
861 hln2b = hlb(1, 2); hlp2b = hlb(2, 2)
863 wa = [ hln1a * hln2a, hln1a * hlp2a, hlp1a * hln2a, hlp1a * hlp2a ]
864 wb = [ hln1b * hln2b, hln1b * hlp2b, hlp1b * hln2b, hlp1b * hlp2b ]
873 sgn = merge(+1, -1, mod(i, 2) == 0)
874 pa(a) = pa(a) + sgn*cx
881 do ifun = 1, levin_dim
882 contrib_a = wa(ifun) * pa(ifun)
883 contrib_b = wb(ifun) * pb(ifun)
884 delta = contrib_b - contrib_a
885 integ = integ + delta