Multidip  1.0
Multi-photon matrix elements
multidip_levin.f90
Go to the documentation of this file.
1 ! Copyright 2021
2 !
3 ! For a comprehensive list of the developers that contributed to these codes
4 ! see the UK-AMOR website.
5 !
6 ! This file is part of UKRmol-out (UKRmol+ suite).
7 !
8 ! UKRmol-out is free software: you can redistribute it and/or modify
9 ! it under the terms of the GNU General Public License as published by
10 ! the Free Software Foundation, either version 3 of the License, or
11 ! (at your option) any later version.
12 !
13 ! UKRmol-out is distributed in the hope that it will be useful,
14 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ! GNU General Public License for more details.
17 !
18 ! You should have received a copy of the GNU General Public License
19 ! along with UKRmol-out (in source/COPYING). Alternatively, you can also visit
20 ! <https://www.gnu.org/licenses/>.
21 !
38 
39  use precisn_gbl, only: wp
40 
41  implicit none
42 
43 contains
44 
69  subroutine nested_cgreen_correct_levin (Z, a, b, c, N, sa, sb, m, l, k, v)
70 
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
75 
76  ! WARNING: Implemented for 1D integrals only
77  v = v + levin_adapt(z, a, b, c, m(1), sa, sb, l(1), l(2), k(1), k(2))
78 
79  end subroutine nested_cgreen_correct_levin
80 
81 
133  complex(wp) function levin_adapt (Z, ra, rb, c, m, s1, s2, l1, l2, k1, k2) result (integ)
134 
136 
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
140 
141  integer, parameter :: max_intervals = 2**max_levin_level
142 
143  integer :: depth
144  logical :: converged(max_intervals)
145  complex(wp) :: estimates(max_intervals)
146  complex(wp) :: hl_buffer(2, 2, max_intervals + 1)
147 
148  ! at the beginning the integral over the whole integration range is definitely not converged
149  converged(1) = .false.
150 
151  ! for all binary subdivision orders
152  do depth = 0, max_levin_level - 1
153 
154  ! precalculate Coulomb function in subinterval endpoints for this subdivision of the integration interval
155  call levin_prepare(z, ra, rb, s1, s2, l1, l2, k1, k2, depth, converged, hl_buffer)
156 
157  ! improve accuracy of not-yet-converged subintervals from previous subdivision
158  call levin_improve(z, ra, rb, c, m, l1, l2, k1, k2, 0, 1, depth, converged, hl_buffer, estimates)
159 
160  ! abort on NaN
161  if (.not. estimates(1) == estimates(1)) then
162  print '(a)', 'WARNING: NaN encountered during Levin quadrature'
163  exit
164  end if
165 
166  ! if the top-level integral converged, terminate
167  if (converged(1)) exit
168 
169  end do
170 
171  ! if full subdivision allowance was exhausted without convergence, complain
172  if (depth == max_levin_level) then
173  print '(A,I0,A)', 'WARNING: Adaptive Levin integration did not converge in ', max_levin_level, ' subdivisions'
174  end if
175 
176  ! return the best stimate of the top-level integration interval
177  integ = estimates(1)
178 
179  end function levin_adapt
180 
181 
204  subroutine levin_prepare (Z, ra, rb, s1, s2, l1, l2, k1, k2, depth, converged, Hl_buffer)
205 
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(:)
211 
212  real(wp) :: r
213  integer :: num_intervals, first_interval_idx, interval_idx, parent_interval_idx, evaluation_point_idx, storage_point_idx
214 
215  num_intervals = 2**depth
216  first_interval_idx = 2**depth
217 
218  ! when called for the first time, evaluate Coulomb functions at the end points of the total integration range
219  if (depth == 0) then
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))
222  return
223  end if
224 
225  ! evaluate Coulomb functions in all other needed points at this subdivision level
226  do interval_idx = first_interval_idx, first_interval_idx + num_intervals - 1, 2
227 
228  ! check if the parent interval (if any) of this sub-interval is converged
229  if (depth > 0) then
230 
231  parent_interval_idx = interval_idx / 2
232 
233  ! if yes, mark this sub-interval as converged, too, and move on
234  if (converged(parent_interval_idx)) then
235  converged(interval_idx) = .true.
236  converged(interval_idx + 1) = .true.
237  cycle
238  end if
239 
240  end if
241 
242  ! otherwise mark it as unconverged
243  converged(interval_idx) = .false.
244  converged(interval_idx + 1) = .false.
245 
246  ! only odd index (new in this subdivision level) needs to be precomputed, which is the right endpoint of this interval
247  evaluation_point_idx = interval_idx + 1
248  storage_point_idx = (evaluation_point_idx + 3)/2
249 
250  ! calculate position
251  r = ra + (evaluation_point_idx - first_interval_idx) * (rb - ra) / num_intervals
252 
253  ! perform the evaluation of Coulomb functions
254  call levin_eval(z, r, s1, s2, l1, l2, k1, k2, hl_buffer(:, :, storage_point_idx))
255 
256  end do
257 
258  end subroutine levin_prepare
259 
260 
285  subroutine levin_eval (Z, r, s1, s2, l1, l2, k1, k2, Hl)
286 
287  use multidip_special, only: coulh
288 
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)
293 
294  real(wp) :: Ek1, Ek2
295 
296  ek1 = real(k1**2, wp)/2
297  ek2 = real(k2**2, wp)/2
298 
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)
303 
304  end subroutine levin_eval
305 
306 
336  recursive subroutine levin_improve (Z, ra, rb, c, m, l1, l2, k1, k2, depth, interval_idx, tgt_depth, converged, Hl, estimates)
337 
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(:)
344 
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
349 
350  complex(wp) :: best_estimate,improved_estimate
351 
352  ! at the target depth simply evaluate the integrals over the given subinterval and store the estimates
353  if (depth == tgt_depth) then
354 
355  num_local_intervals = 2**depth
356  first_interval_idx = 2**depth
357  max_global_point_idx = 2**(depth + 1)
358 
359  left_point_global_idx = interval_idx;
360  right_point_global_idx = left_point_global_idx + 1
361 
362  left_point_local_idx = interval_idx - first_interval_idx
363  right_point_local_idx = left_point_local_idx + 1
364 
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))
367 
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)
370 
371  a = ra + left_point_local_idx * (rb - ra) / num_local_intervals
372  b = ra + right_point_local_idx * (rb - ra) / num_local_intervals
373 
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))
377 
378  return
379 
380  end if
381 
382  ! get subinterval indices
383  left_subinterval_idx = 2*interval_idx;
384  right_subinterval_idx = 2*interval_idx + 1;
385 
386  ! update all non-converged sub-intervals
387  if (.not. converged(left_subinterval_idx)) then
388  call levin_improve(z, ra, rb, c, m, l1, l2, k1, k2, &
389  depth + 1, left_subinterval_idx, tgt_depth, converged, hl, estimates)
390  end if
391  if (.not. converged(right_subinterval_idx)) then
392  call levin_improve(z, ra, rb, c, m, l1, l2, k1, k2, &
393  depth + 1, right_subinterval_idx, tgt_depth, converged, hl, estimates)
394  end if
395 
396  ! check convergence by comparing estimate for this interval to the sum of the estimates for the two sub.intervals
397  best_estimate = estimates(interval_idx)
398  improved_estimate = estimates(left_subinterval_idx) + estimates(right_subinterval_idx)
399  epsrel = 1e-7
400  epsabs = epsrel * abs(estimates(1)) ! TODO ... take into account there are more unconverged subintervals in this depth
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.
407  end if
408 
409  ! update the estimate for this interval with the sum of estimates for the two subintervals
410  estimates(interval_idx) = improved_estimate
411 
412  end subroutine levin_improve
413 
414 
442  complex(wp) function levin_integrate (Z, ra, rb, c, m, l1, l2, k1, k2, Hla, Hlb) result (integ)
443 
444  use mpi_gbl, only: mpi_xermsg
445 
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)
450 
451  if (aimag(k1) == 0 .and. aimag(k2) == 0) then
452  ! free-free transition, both Coulomb functions have positive energy and oscillate -> use 4-dimensional Levin integrator
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
455  ! free-closed transition, only H1 has positive energy and oscillates -> use 2-dimensional Levin integrator
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
458  ! closed-free transition, only H2 has positive energy and oscillates -> use 2-dimensional Levin integrator
459  integ = levin_integrate_2x2(z, ra, rb, c, m, l1, l2, aimag(k1), real(k2, wp), hla(:, 2), hlb(:, 2))
460  else
461  call mpi_xermsg('multidip_levin', 'levin_integrate', 'Levin integrator cannot integrate closed-closed integrals.', 1, 1)
462  end if
463 
464  end function levin_integrate
465 
466 
524  complex(wp) function levin_integrate_2x2 (Z, ra, rb, c, m, lc, lo, kc, ko, wa, wb) result (integ)
525 
526  use blas_lapack_gbl, only: blasint
527  use mpi_gbl, only: mpi_xermsg
528  use multidip_params, only: rone, rhalf, cheb_order
529  use multidip_special, only: blas_dgetrf => dgetrf, blas_dgetrs => dgetrs, coulh
530  use phys_const_gbl, only: pi
531 
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)
535 
536  integer, parameter :: levin_dim = 2
537  integer, parameter :: mat_dim = levin_dim * (cheb_order + 1)
538 
539  integer :: ipoly, inode, a, b, i, j, row, col, sgn, ifun, flips
540 
541  real(wp) :: x, r, rl, elem, cx
542  real(wp) :: cheb_node(0 : cheb_order)
543  real(wp) :: cheb_value(0 : cheb_order, 0 : cheb_order)
544  real(wp) :: cheb_deriv(0 : cheb_order, 0 : cheb_order)
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)
550 
551  complex(wp) :: hlna, hlnb, hlpa, hlpb, wl
552  complex(wp) :: contrib_a, contrib_b, delta
553 
554  integer(blasint) :: n, pivots(mat_dim), info
555 
556  ! only allow positive non-empty intervals
557  if (ra >= rb) then
558  call mpi_xermsg('multidip_levin', 'levin_integrate_2x2', &
559  'Levin integration not implemented for non-positive intervals', 1, 1)
560  end if
561 
562  ! populate split matrices of the recurrence relations (total matrix is LevinA = Aa/r + Ab)
563  rl = sqrt(ko*ko + z*z/((lo + 1)*(lo + 1)))
564 
565  aa(1, 1) = + lo + 1; aa(1, 2) = 0
566  aa(2, 1) = 0; aa(2, 2) = - lo - 1
567 
568  ab(1, 1) = -z/(lo + 1); ab(1, 2) = -rl
569  ab(2, 1) = +rl; ab(2, 2) = +z/(lo + 1)
570 
571  ! evaluate Chebyshev nodes as well as Chebyshev polynomials and their derivatives in these nodes
572  do inode = 0, cheb_order
573 
574  x = cos((inode + rhalf) * pi / (cheb_order + 1))
575 
576  cheb_node(inode) = x
577 
578  cheb_value(inode, 0) = 1; cheb_deriv(inode, 0) = 0
579  cheb_value(inode, 1) = x; cheb_deriv(inode, 1) = 1
580 
581  do ipoly = 1, cheb_order - 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)
585  end do
586 
587  end do
588 
589  ! construct the matrix of the equations
590  do a = 1, levin_dim
591  do i = 0, cheb_order
592  row = (a - 1) * (cheb_order + 1) + i + 1
593  do b = 1, levin_dim
594  do j = 0, cheb_order
595  col = (b - 1) * (cheb_order + 1) + j + 1
596  x = cheb_node(i)
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)
600  if (a == b) then
601  mat(row, col) = mat(row, col) + 2/(rb - ra) * cheb_deriv(i, j)
602  end if
603  end do
604  end do
605  end do
606  end do
607 
608  ! construct the right-hand side (only populate elements pertaining to the first function)
609  do a = 1, levin_dim
610  do i = 0, cheb_order
611  row = (a - 1) * (cheb_order + 1) + i + 1
612  x = cheb_node(i)
613  r = ra + (x + 1) * (rb - ra) / 2
614  if (a == 1) then
615  wl = real(coulh(z, 0, lc, -kc*kc/2, r), wp)
616  coef(row) = r**m * exp(-c*r) * wl
617  else
618  coef(row) = 0
619  end if
620  end do
621  end do
622 
623  ! solve the set of equations
624  n = mat_dim
625  call blas_dgetrf(n, n, mat, n, pivots, info)
626  if (info /= 0) then
627  call mpi_xermsg('multidip_levin', 'levin_integrate_2x2', &
628  'LU decomposition in Levin integration failed', int(info), 1)
629  end if
630  call blas_dgetrs('N', n, 1_blasint, mat, n, pivots, coef, n, info)
631  if (info /= 0) then
632  call mpi_xermsg('multidip_levin', 'levin_integrate_2x2', &
633  'LU backsubstitution in Levin integration failed', int(info), 1)
634  end if
635 
636  ! evaluate the boundary terms
637  do a = 1, levin_dim
638  pa(a) = 0
639  pb(a) = 0
640  do i = 0, cheb_order
641  row = (a - 1) * (cheb_order + 1) + i + 1
642  cx = coef(row)
643  sgn = merge(+1, -1, mod(i, 2) == 0)
644  pa(a) = pa(a) + sgn*cx
645  pb(a) = pb(a) + cx
646  end do
647  end do
648 
649  ! evaluate the integral
650  integ = 0
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
656  end do
657 
658  end function levin_integrate_2x2
659 
660 
720  complex(wp) function levin_integrate_4x4 (Z, ra, rb, c, m, l1, l2, k1, k2, Hla, Hlb) result (integ)
721 
722  use blas_lapack_gbl, only: blasint
723  use mpi_gbl, only: mpi_xermsg
724  use multidip_params, only: rone, rhalf, cheb_order
725  use multidip_special, only: blas_dgetrf => dgetrf, blas_dgetrs => dgetrs
726  use phys_const_gbl, only: pi
727 
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)
731 
732  integer, parameter :: levin_dim = 4
733  integer, parameter :: mat_dim = levin_dim * (cheb_order + 1)
734 
735  integer :: ipoly, inode, a, b, i, j, row, col, sgn, ifun, flips
736 
737  real(wp) :: x, r, r1, r2, elem, cx
738  real(wp) :: cheb_node(0 : cheb_order)
739  real(wp) :: cheb_value(0 : cheb_order, 0 : cheb_order)
740  real(wp) :: cheb_deriv(0 : cheb_order, 0 : cheb_order)
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)
746 
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
749 
750  integer(blasint) :: n, pivots(mat_dim), info
751 
752  ! only allow positive non-empty intervals
753  if (ra >= rb) then
754  call mpi_xermsg('multidip_levin', 'levin_integrate_4x4', &
755  'Levin integration not implemented for non-positive intervals', 1, 1)
756  end if
757 
758  ! populate split matrices of the recurrence relations (total matrix is LevinA = Aa/r + Ab)
759  aa = 0
760  ab = 0
761 
762  r1 = sqrt(k1*k1 + z/((l1 + 1)*(l1 + 1)))
763  r2 = sqrt(k2*k2 + z/((l2 + 1)*(l2 + 1)))
764 
765  aa(1, 1) = + l1 + l2 + 2
766  aa(2, 2) = + l1 - l2
767  aa(3, 3) = - l1 + l2
768  aa(4, 4) = - l1 - l2 - 2
769 
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)
774 
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
779 
780  ! evaluate Chebyshev nodes as well as Chebyshev polynomials and their derivatives in these nodes
781  do inode = 0, cheb_order
782 
783  x = cos((inode + rhalf) * pi / (cheb_order + 1))
784 
785  cheb_node(inode) = x
786 
787  cheb_value(inode, 0) = 1; cheb_deriv(inode, 0) = 0
788  cheb_value(inode, 1) = x; cheb_deriv(inode, 1) = 1
789 
790  do ipoly = 1, cheb_order - 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)
794  end do
795 
796  end do
797 
798  ! construct the matrix of the equations
799  do a = 1, levin_dim
800  do i = 0, cheb_order
801  row = (a - 1) * (cheb_order + 1) + i + 1
802  do b = 1, levin_dim
803  do j = 0, cheb_order
804  col = (b - 1) * (cheb_order + 1) + j + 1
805  x = cheb_node(i)
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)
809  if (a == b) then
810  mat(row, col) = mat(row, col) + 2/(rb - ra) * cheb_deriv(i, j)
811  end if
812  end do
813  end do
814  !print '(8x,SP,*(E10.3,1x))', real(mat(row, :), wp)
815  end do
816  end do
817 
818  ! construct the right-hand side (only populate elements pertaining to the first function)
819  do a = 1, levin_dim
820  do i = 0, cheb_order
821  row = (a - 1) * (cheb_order + 1) + i + 1
822  x = cheb_node(i)
823  r = ra + (x + 1) * (rb - ra) / 2
824  if (a == 1) then
825  coef(row) = r**m * exp(-c*r)
826  else
827  coef(row) = 0
828  end if
829  end do
830  end do
831 
832  ! solve the set of equations
833  n = mat_dim
834  call blas_dgetrf(n, n, mat, n, pivots, info)
835  if (info /= 0) then
836  call mpi_xermsg('multidip_levin', 'levin_integrate_4x4', &
837  'LU decomposition in Levin integration failed', int(info), 1)
838  end if
839  call blas_dgetrs('N', n, 1_blasint, mat, n, pivots, coef, n, info)
840  if (info /= 0) then
841  call mpi_xermsg('multidip_levin', 'levin_integrate_4x4', &
842  'LU backsubstitution in Levin integration failed', int(info), 1)
843  end if
844 
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)
849 
850  wa = [ hln1a * hln2a, hln1a * hlp2a, hlp1a * hln2a, hlp1a * hlp2a ]
851  wb = [ hln1b * hln2b, hln1b * hlp2b, hlp1b * hln2b, hlp1b * hlp2b ]
852 
853  ! evaluate the boundary terms
854  do a = 1, levin_dim
855  pa(a) = 0
856  pb(a) = 0
857  do i = 0, cheb_order
858  row = (a - 1) * (cheb_order + 1) + i + 1
859  cx = coef(row)
860  sgn = merge(+1, -1, mod(i, 2) == 0)
861  pa(a) = pa(a) + sgn*cx
862  pb(a) = pb(a) + cx
863  end do
864  end do
865 
866  ! evaluate the integral
867  integ = 0
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
873  end do
874 
875  end function levin_integrate_4x4
876 
877 end module multidip_levin
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
real(wp), parameter rone
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.