Multidip  1.0
Multi-photon matrix elements
multidip_special.F90
Go to the documentation of this file.
1 ! Copyright 2020
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 !
27 
28  use, intrinsic :: iso_c_binding, only: c_double, c_int, c_f_pointer
29  use, intrinsic :: iso_fortran_env, only: error_unit, input_unit, int32, int64, real64, output_unit
30 
31  use blas_lapack_gbl, only: blasint
32  use phys_const_gbl, only: pi, imu
33  use precisn_gbl, only: wp
34 
35  implicit none
36 
37 #ifdef WITH_GSL
38 
39  type, bind(C) :: gsl_sf_result
40  real(c_double) :: val
41  real(c_double) :: err
42  end type gsl_sf_result
43 
44  interface
45  ! switch off the hard error handler
46  function gsl_set_error_handler_off () bind(C, name='gsl_set_error_handler_off')
47  use, intrinsic :: iso_c_binding, only: c_ptr
48  type(c_ptr) :: gsl_set_error_handler_off
49  end function gsl_set_error_handler_off
50  end interface
51 
52  interface
53  ! logarithm of the complex gamma function from GSL
54  function gsl_sf_lngamma_complex_e (zr, zi, lnr, arg) bind(C, name='gsl_sf_lngamma_complex_e')
55  use, intrinsic :: iso_c_binding, only: c_int, c_double
56  import gsl_sf_result
57  real(c_double), value :: zi, zr
58  type(gsl_sf_result) :: lnr, arg
59  integer(c_int) :: gsl_sf_lngamma_complex_e
60  end function gsl_sf_lngamma_complex_e
61  end interface
62 
63  interface
64  ! Coulomb wave function from GSL
65  function gsl_sf_coulomb_wave_fg_e (eta, rho, l, k, F, Fp, G, Gp, expF, expG) bind(C, name='gsl_sf_coulomb_wave_FG_e')
66  use, intrinsic :: iso_c_binding, only: c_int, c_double
67  import gsl_sf_result
68  real(c_double), value :: eta, rho, l
69  integer(c_int), value :: k
70  type(gsl_sf_result) :: F, Fp, G, Gp
71  real(c_double) :: expF, expG
72  integer(c_int) :: gsl_sf_coulomb_wave_FG_e
73  end function gsl_sf_coulomb_wave_fg_e
74  end interface
75 
76  interface
77  ! irregular confluent hypergeometric function U
78  pure function gsl_sf_hyperg_u (a, b, x) bind(C, name='gsl_sf_hyperg_U')
79  use, intrinsic :: iso_c_binding, only: c_double
80  real(c_double), value :: a, b, x
81  real(c_double) :: gsl_sf_hyperg_U
82  end function gsl_sf_hyperg_u
83  end interface
84 #endif
85 
86  interface
87  ! Coulomb phase from UKRmol-out
88  function cphaz (l, eta, iwrite)
89  import wp
90  integer :: l, iwrite
91  real(wp) :: eta, cphaz
92  end function cphaz
93  end interface
94 
95  interface
96  ! Coulomb wave function from UKRmol-out
97  subroutine coulfg (xx, eta1, xlmin, xlmax, fc, gc, fcp, gcp, mode1, kfn, ifail)
98  import wp
99  integer :: mode1, kfn, ifail
100  real(wp) :: xx, eta1, xlmin, xlmax, fc(*), gc(*), fcp(*), gcp(*)
101  end subroutine coulfg
102  end interface
103 
104  interface
105  ! Decaying Whittaker function
106  subroutine couln (l, Z, ERy, r, U, Up, acc, efx, ierr, nlast, fnorm)
107  import wp
108  integer :: l, ierr, nlast
109  real(wp) :: Z, Ery, r, U, Up, acc, efx, fnorm
110  end subroutine couln
111  end interface
112 
113  interface
114  !Exponentially decaying solution with given (negative) energy and angular momentum
115  subroutine decay (k, l, r, U, Up, iwrite)
116  import wp
117  integer :: l, iwrite
118  real(wp) :: k, r, U, Up
119  end subroutine decay
120  end interface
121 
122  interface
123  ! real matrix-matrix multiplication from BLAS
124  subroutine dgemm (transa, transb, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc)
125  import real64, blasint
126  character(len=1) :: transa, transb
127  integer(blasint) :: m, n, k, lda, ldb, ldc
128  real(real64) :: A(lda, *), B(ldb, *), C(ldc, *), alpha, beta
129  end subroutine dgemm
130  end interface
131 
132  interface
133  ! real matrix-vector multiplication from BLAS
134  subroutine dgemv (trans, m, n, alpha, A, lda, X, incx, beta, Y, incy)
135  import real64, blasint
136  character(len=1) :: trans
137  integer(blasint) :: m, n, incx, incy, lda
138  real(real64) :: A(lda, *), X(*), Y(*), alpha, beta
139  end subroutine dgemv
140  end interface
141 
142  interface
143  ! real symmetric matrix eigendecomposition from LAPACK
144  subroutine dsyev (jobz, uplo, n, A, lda, eigs, work, lwork, info)
145  import real64, blasint
146  character(len=1) :: jobz, uplo
147  integer(blasint) :: n, lda, lwork, info
148  real(real64) :: A(lda, *), eigs(*), work(*)
149  end subroutine dsyev
150  end interface
151 
152  interface
153  ! real LU decomposition from LAPACK
154  subroutine dgetrf (m, n, A, lda, ipiv, info)
155  import real64, blasint
156  integer(blasint) :: m, n, lda, ipiv(*), info
157  real(real64) :: A(lda, *)
158  end subroutine dgetrf
159  end interface
160 
161  interface
162  ! real LU backsubstitution from LAPACK
163  subroutine dgetrs (trans, n, nrhs, A, lda, ipiv, B, ldb, info)
164  import real64, blasint
165  character(len=1) :: trans
166  integer(blasint) :: n, nrhs, lda, ldb, info, ipiv(*)
167  real(real64) :: A(lda, *), B(ldb, *)
168  end subroutine dgetrs
169  end interface
170 
171  interface
172  ! complex matrix-matrix multiplication from BLAS
173  subroutine zgemm (transa, transb, m, n, k, alpha, A, lda, B, ldb, beta, C, ldc)
174  import real64, blasint
175  character(len=1) :: transa, transb
176  integer(blasint) :: m, n, k, lda, ldb, ldc
177  complex(real64) :: A(lda, *), B(ldb, *), C(ldc, *), alpha, beta
178  end subroutine zgemm
179  end interface
180 
181  interface
182  ! complex matrix-vector multiplication from BLAS
183  subroutine zgemv (trans, m, n, alpha, A, lda, X, incx, beta, Y, incy)
184  import real64, blasint
185  character(len=1) :: trans
186  integer(blasint) :: m, n, incx, incy, lda
187  complex(real64) :: A(lda, *), X(*), Y(*), alpha, beta
188  end subroutine zgemv
189  end interface
190 
191  interface
192  ! complex LU decomposition from LAPACK
193  subroutine zgetrf (m, n, A, lda, ipiv, info)
194  import real64, blasint
195  integer(blasint) :: m, n, lda, ipiv(*), info
196  complex(real64) :: A(lda, *)
197  end subroutine zgetrf
198  end interface
199 
200  interface
201  ! complex LU backsubstitution from LAPACK
202  subroutine zgetrs (trans, n, nrhs, A, lda, ipiv, B, ldb, info)
203  import real64, blasint
204  character(len=1) :: trans
205  integer(blasint) :: n, nrhs, lda, ldb, info, ipiv(*)
206  complex(real64) :: A(lda, *), B(ldb, *)
207  end subroutine zgetrs
208  end interface
209 
210  interface
211  ! complex matrix inversion from LAPACK
212  subroutine zgetri (n, A, lda, ipiv, work, lwork, info)
213  import real64, blasint
214  integer(blasint) :: n, lda, ipiv(*), lwork, info
215  complex(real64) :: A(lda, *), work(*)
216  end subroutine zgetri
217  end interface
218 
219 contains
220 
237  subroutine calculate_r_matrix (nchan, nstat, wmat, eig, Etot, Rmat)
238 
239  integer, intent(in) :: nchan, nstat
240  real(wp), intent(in) :: wmat(:, :), eig(:), Etot
241  real(wp), intent(inout) :: Rmat(:, :)
242  real(wp), allocatable :: E_wmat(:, :)
243  integer(blasint) :: lda, ldc, n, m, istat
244 
245  allocate (e_wmat(nchan, nstat))
246 
247  lda = size(wmat, 1)
248  ldc = size(rmat, 1)
249 
250  n = nchan
251  m = nstat
252 
253  !$omp parallel do private(istat)
254  do istat = 1, nstat
255  e_wmat(1:nchan, istat) = wmat(1:nchan, istat) / (eig(istat) - etot)
256  end do
257 
258  call dgemm('N', 'T', n, n, m, 0.5_wp, wmat, lda, e_wmat, n, 0.0_wp, rmat, ldc)
259 
260  end subroutine calculate_r_matrix
261 
262 
273  subroutine calculate_t_matrix (K, T, nopen)
274 
275  use multidip_params, only: rone, rzero
276 
277  real(wp), intent(in) :: K(:, :)
278  complex(wp), intent(inout) :: T(:, :)
279  integer, intent(in) :: nopen
280 
281  integer(blasint) :: i, j, n, one = 1, ldk, info
282  integer(blasint), allocatable :: ipiv(:)
283  real(wp), allocatable :: A(:, :), ReT(:, :), ImT(:, :)
284 
285  allocate (a(nopen, nopen), ipiv(nopen), ret(nopen, nopen), imt(nopen, nopen))
286 
287  n = nopen
288  ldk = size(k, 1)
289 
290  !$omp parallel do private(i, j)
291  do j = 1, nopen
292  do i = 1, nopen
293  imt(i, j) = 2*k(i, j)
294  end do
295  end do
296 
297  call dgemm('T', 'N', n, n, n, rone, k, ldk, k, ldk, rzero, a, n)
298 
299  !omp parallel do
300  do i = 1, nopen
301  a(i, i) = 1 + a(i, i)
302  end do
303 
304  call dgetrf(n, n, a, n, ipiv, info)
305 
306  if (info /= 0) then
307  print '(a)', 'ERROR: Failed to factorize 1 + K^2'
308  stop 1
309  end if
310 
311  call dgetrs('N', n, n, a, n, ipiv, imt, n, info)
312 
313  if (info /= 0) then
314  print '(a)', 'ERROR: Failed to back-substitute (1 + K^2) X = 2K'
315  stop 1
316  end if
317 
318  call dgemm('T', 'N', n, n, n, -rone, k, ldk, imt, n, rzero, ret, n)
319 
320  !$omp parallel do private (i, j)
321  do j = 1, nopen
322  do i = 1, nopen
323  t(i, j) = cmplx(ret(i, j), imt(i, j), wp)
324  end do
325  end do
326 
327  end subroutine calculate_t_matrix
328 
329 
339  subroutine calculate_s_matrix (T, S, nopen)
340 
341  use multidip_params, only: cone, czero
342 
343  complex(wp), intent(inout) :: S(:, :)
344  complex(wp), intent(in) :: T(:, :)
345  integer, intent(in) :: nopen
346 
347  integer :: i, j
348 
349  !$omp parallel do
350  do j = 1, nopen
351  s(1:nopen, j) = t(1:nopen, j)
352  s(j, j) = 1 + s(j, j)
353  end do
354 
355  end subroutine calculate_s_matrix
356 
357 
373  subroutine scatak (rmatr, eig, etot, w, Ek, l, Km, Ak)
374 
375  use multidip_params, only: rzero, rone
376 
377  complex(wp), intent(inout) :: Ak(:,:)
378  real(wp), intent(in) :: rmatr, eig(:), etot, Ek(:), w(:,:), Km(:,:)
379  integer, intent(in) :: l(:)
380 
381  complex(wp), allocatable :: T(:,:)
382  real(wp), allocatable :: V(:,:), TT(:,:,:), Sp(:,:), Cp(:,:), P(:), XX(:,:,:), wFp(:,:,:), k(:)
383 
384  integer(blasint) :: i, j, nchan, nstat, nopen, nochf, nochf2, ldwmp
385  real(wp) :: F, Fp, G, Gp, Z = 1
386 
387  nchan = size(km, 1) ! number of channels
388  nopen = count(ek > 0) ! number of open channels
389  nochf = size(ak, 2) ! number of channels for which to calcualte the Ak coefficients
390  nstat = size(eig) ! number of inner eigenstates for this irreducible representation
391  ldwmp = size(w, 1) ! leading dimension of the matrix where the boundary amplitudes are stored
392  k = sqrt(2*abs(ek)) ! linear momentum of the photoelectron
393 
394  nopen = min(nopen, nchan)
395  nochf = min(nopen, nochf)
396  nochf2 = 2*nochf
397 
398  allocate (v(nchan, nchan), t(nopen, nopen), sp(nchan, nchan), cp(nchan, nchan), tt(nchan, 2, nopen), &
399  xx(nchan, 2, nochf), wfp(nstat, 2, nochf), p(nstat))
400 
401  t = 0; v = 0; sp = 0; cp = 0
402 
403  ! construct, factorize and invert for T = (1 + iK)⁻¹ (nopen-by-nopen)
404  do i = 1, nopen
405  t(i,i) = 1
406  end do
407  t = t + imu*km(1:nopen, 1:nopen)
408  call invert_matrix(t)
409  tt(1:nopen, 1, 1:nochf) = real(t(1:nopen, 1:nochf), wp)
410  tt(1:nopen, 2, 1:nochf) = aimag(t(1:nopen, 1:nochf))
411 
412  ! evaluate the Coulomb functions and the normalization factor (nchan-by-nchan)
413  do i = 1, nchan
414  call coul(z, l(i), ek(i), rmatr, f, fp, g, gp)
415  v(i,i) = sqrt(2/(pi*k(i)))
416  sp(i,i) = fp
417  cp(i,i) = gp
418  end do
419 
420  ! wave function coefficient (nstat-by-nochf)
421  call dgemm('N', 'N', nchan, nopen, nchan, rone, cp, nchan, km, nchan, rone, sp, nchan) ! S' + C' K
422  call dgemm('N', 'N', nchan, nochf2, nopen, rone, sp, nchan, tt, nchan, rzero, xx, nchan) ! (S' + C' K) T
423  call dgemm('N', 'N', nchan, nochf2, nchan, rone, v, nchan, xx, nchan, rzero, tt, nchan) ! V (S' + C' K) T
424  call dgemm('T', 'N', nstat, nochf2, nchan, rone, w, ldwmp, tt, nchan, rzero, wfp, nstat) ! wT V (S' + C' K) T
425  p = 0.5 / (eig - etot)
426  do i = 1, nochf
427  ak(:, i) = p * cmplx(wfp(:, 1, i), wfp(:, 2, i), wp)
428  end do
429 
430  end subroutine scatak
431 
432 
440  real(wp) function cphase (z, l, k) result (sigma)
441 
442  integer, intent(in) :: l
443  real(wp), intent(in) :: z, k
444 #ifdef WITH_GSL
445  type(gsl_sf_result) :: lnr, arg
446  integer(c_int) :: err
447  real(c_double) :: zr, zi
448 
449  zr = l + 1
450  zi = -z/k
451  err = gsl_sf_lngamma_complex_e(zr, zi, lnr, arg)
452  sigma = arg % val
453 #else
454  sigma = cphaz(l, -z/k, 0)
455 #endif
456 
457  end function cphase
458 
459 
466  recursive complex(wp) function complex_gamma (l, x) result (G)
467 
468  real(wp), intent(in) :: x
469  integer, intent(in) :: l
470 
471  real(wp) :: absval, phase, z = 1
472  integer :: k
473 
474  ! case without x reduces to l!
475  if (x == 0) then
476  g = 1
477  do k = 2, l
478  g = g * k
479  end do
480  return
481  end if
482 
483  ! use reflection formula for negative l
484  if (l < 0) then
485  g = imu * (-1)**l * pi / (sinh(pi*x) * complex_gamma(-l - 1, -x))
486  return
487  end if
488 
489  ! absolute value from a closed formula from Wikipedia
490  absval = 1
491  do k = 1, l
492  absval = absval * (k**2 + x**2)
493  end do
494  absval = absval * pi*x/sinh(pi*x)
495  absval = sqrt(absval)
496 
497  ! phase is the Coulomb phase
498  phase = cphase(z, l, -1/x)
499 
500  ! final result
501  g = absval * cmplx(cos(phase), sin(phase), wp)
502 
503  end function complex_gamma
504 
505 
518  subroutine coul (Z, l, Ek, r, F, Fp, G, Gp)
519 
520  integer, intent(in) :: l
521  real(wp), intent(in) :: Z, Ek, r
522  real(wp), intent(inout) :: F, Fp, G, Gp
523 #ifdef WITH_GSL
524  call coul_gsl(z, l, ek, r, f, fp, g, gp)
525 #else
526  call coul_ukrmol(z, l, ek, r, f, fp, g, gp)
527 #endif
528  end subroutine coul
529 
530 
537  complex(wp) function coulh (Z, s, l, Ek, r) result(H)
538 
539  integer, intent(in) :: s, l
540  real(wp), intent(in) :: z, ek, r
541 
542  real(wp) :: f, fp, g, gp
543 
544  call coul(z, l, ek, r, f, fp, g, gp)
545 
546  h = cmplx(g, s*f, wp)
547 
548  end function coulh
549 
550 
561  complex(wp) function coulh_asy (Z, s, l, Ek, r) result(H)
562 
563  use multidip_params, only: ntermsasy
564 
565  integer, intent(in) :: s, l
566  real(wp), intent(in) :: z, ek, r
567 
568  integer :: n
569  complex(wp) :: a, b, term
570  real(wp) :: k
571 
572  k = sqrt(2*abs(ek))
573 
574  if (ek > 0) then
575  a = l + 1 - z*imu/k
576  b = -l - z*imu/k
577  else
578  a = l + 1 - z/k
579  b = -l - z/k
580  end if
581 
582  term = 1
583  h = 1
584 
585  do n = 1, ntermsasy
586  if (ek > 0) then
587  term = term * (a + n - 1) * (b + n - 1) / (2*s*imu*n*k*r)
588  else
589  term = term * (a + n - 1) * (b + n - 1) / (-2*s*n*k*r)
590  end if
591  h = h + term
592  end do
593 
594  if (ek > 0) then
595  h = h * exp(imu*s*(k*r + z*log(2*k*r)/k - pi*l/2 + cphase(z, l, k)))
596  else
597  h = h * exp(s*(-k*r + z*log(2*k*r)/k))
598  end if
599 
600  end function coulh_asy
601 
602 
611  subroutine coul_gsl (Z, l, Ek, r, F, Fp, G, Gp)
612 
613  integer, intent(in) :: l
614  real(wp), intent(in) :: Z, Ek, r
615  real(wp), intent(inout) :: F, Fp, G, Gp
616 #ifdef WITH_GSL
617  type(gsl_sf_result) :: resF, resFp, resG, resGp
618  real(c_double) :: expF, expG, eta, rho, lc, k, a, b, x, U, Up
619  integer(c_int) :: err, zero = 0
620 
621  if (ek > 0) then
622  ! positive-energy solution
623  k = sqrt(2*ek)
624  rho = k*r
625  eta = -z/k
626  lc = l
627  err = gsl_sf_coulomb_wave_fg_e(eta, rho, lc, zero, resf, resfp, resg, resgp, expf, expg)
628  f = resf % val
629  fp = resfp % val * k
630  g = resg % val
631  gp = resgp % val * k
632  else
633  ! negative-energy solution, Whittaker function W (WARNING: charged only)
634  k = sqrt(-2*ek)
635  a = l + 1 - z/k
636  b = 2*l + 2
637  x = 2*k*r
638  u = gsl_sf_hyperg_u(a, b, x)
639  up = -2*k*a * gsl_sf_hyperg_u(a + 1, b + 1, x) ! DLMF §13.3.22
640  f = 0
641  fp = 0
642  g = exp(-x/2) * x**(l + 1) * u ! DLMF §13.14.3
643  gp = exp(-x/2) * x**(l + 1) * (-k * u + (l + 1)/r * u + up)
644  end if
645 #else
646  f = 0; fp = 0
647  g = 0; gp = 0
648 #endif
649  end subroutine coul_gsl
650 
651 
660  subroutine coul_ukrmol (Z, l, Ek, r, F, Fp, G, Gp)
661 
662  integer, intent(in) :: l
663  real(wp), intent(in) :: Z, Ek, r
664  real(wp), intent(inout) :: F, Fp, G, Gp
665  integer :: ifail, mode = 1, kfn = 0, nterms, iwrite = 0
666  real(wp) :: fc(l + 1), gc(l + 1), fcp(l + 1), gcp(l + 1), lc, efx, fnorm, acc = 1e-10_wp, k
667 
668  lc = l
669  if (ek > 0) then
670  ! positive-energy solution
671  k = sqrt(2*ek)
672  call coulfg(k*r, -z/k, lc, lc, fc, gc, fcp, gcp, mode, kfn, ifail)
673  f = fc(l + 1)
674  g = gc(l + 1)
675  fp = fcp(l + 1) * k
676  gp = gcp(l + 1) * k
677  else
678  ! negative energy solution (charged or neutral)
679  if (z /= 0) then
680  call couln(l, z, 2*ek, r, g, gp, acc, efx, ifail, nterms, fnorm)
681  else
682  call decay(2*ek, l, r, g, gp, iwrite)
683  end if
684  f = 0
685  fp = 0
686  end if
687 
688  end subroutine coul_ukrmol
689 
690 
703  subroutine diagonalize_symm_matrix (M, eigs, eigv, check)
704 
705  real(wp), intent(in) :: M(:, :)
706  real(wp), intent(inout) :: eigs(:), eigv(:, :)
707  real(wp), intent(in), optional :: check
708 
709  integer(blasint) :: i, n, info, lwork
710  real(wp), allocatable :: work(:), tmp(:, :)
711  real(wp) :: diag, offdiag
712 
713  n = size(eigs)
714  eigv = m
715  allocate (work(1))
716  call dsyev('V', 'U', n, eigv, n, eigs, work, -1_blasint, info)
717 
718  if (info /= 0) then
719  write (error_unit, '(a,i0,a)') 'Error ', info, ' when preparing matrix diagonalization'
720  stop 1
721  end if
722 
723  lwork = work(1)
724  deallocate (work)
725  allocate (work(lwork))
726  call dsyev('V', 'U', n, eigv, n, eigs, work, lwork, info)
727 
728  if (info /= 0) then
729  write (error_unit, '(a,i0,a)') 'Error ', info, ' when diagonalizing matrix'
730  stop 1
731  end if
732 
733  ! fix phase of the eigenvectors (element largest in magnitude has to be positive)
734  do i = 1, n
735  if (eigv(maxloc(abs(eigv(:, i)), 1), i) < 0) then
736  eigv(:, i) = -eigv(:, i)
737  end if
738  end do
739 
740  ! verify that the eigenvector matrix is orthogonal
741  if (present(check)) then
742  if (check > 0) then
743  allocate (tmp(n, n))
744  call dgemm('N', 'T', n, n, n, 1._wp, eigv, n, eigv, n, 0._wp, tmp, n)
745  do i = 1, n
746  diag = tmp(i, i)
747  offdiag = sqrt(sum(abs(tmp(:, i))**2) - diag**2)
748  if (abs(diag - 1) > check .or. abs(offdiag) > check) then
749  write (error_unit, '(a,i0,2e25.15)') 'WARNING: Orthogonality error in symmetric diagonalization ', &
750  i, diag, offdiag
751  stop 1
752  end if
753  end do
754  end if
755  end if
756 
757  end subroutine diagonalize_symm_matrix
758 
759 
766  subroutine invert_matrix (T)
767 
768  complex(wp), allocatable, intent(inout) :: T(:, :)
769 
770  complex(wp), allocatable :: work(:)
771  complex(wp) :: nwork(1)
772 
773  integer(blasint), allocatable :: ipiv(:)
774  integer(blasint) :: m, info, lwork
775 
776  m = size(t, 1)
777 
778  ! calculate LU decomposition
779  allocate (ipiv(m))
780  call zgetrf(m, m, t, m, ipiv, info)
781 
782  ! query for workspace size and allocate memory
783  lwork = -1
784  call zgetri(m, t, m, ipiv, nwork, lwork, info)
785  lwork = int(nwork(1))
786  allocate (work(lwork))
787 
788  ! compute the inverse
789  call zgetri(m, t, m, ipiv, work, lwork, info)
790 
791  end subroutine invert_matrix
792 
793 
801  subroutine solve_complex_system (n, A, X, Y)
802 
803  complex(wp), allocatable, intent(inout) :: A(:, :)
804  real(wp), allocatable, intent(inout) :: X(:, :), Y(:, :)
805  integer, intent(in) :: n
806 
807  integer(blasint) :: m, info, nrhs, lda
808  integer(blasint), allocatable :: ipiv(:)
809  complex(wp), allocatable :: XX(:)
810 
811  allocate (ipiv(n))
812 
813  ! calculate LU decomposition
814  m = n
815  lda = size(a, 1)
816  call zgetrf(m, m, a, lda, ipiv, info)
817 
818  ! combine real and imaginary part of the right-hand side
819  xx = cmplx(x(1:n, 1), x(1:n, 2), wp)
820 
821  ! solve the equation
822  nrhs = 1
823  call zgetrs('N', m, nrhs, a, lda, ipiv, xx, m, info)
824 
825  y(1:n, 1) = real(xx, wp)
826  y(1:n, 2) = aimag(xx)
827 
828  end subroutine solve_complex_system
829 
830 
843  logical function next_permutation (p) result (ok)
844 
845  integer, intent(inout) :: p(:)
846  integer :: i, j, k, n
847 
848  n = size(p)
849 
850  ! no permutation in empty array
851  if (n == 0) then
852  ok = .false.
853  return
854  end if
855 
856  ! initialize a new permutation
857  if (any(p < 1)) then
858  do i = 1, n
859  p(i) = i
860  end do
861  ok = .true.
862  return
863  end if
864 
865  ! one-element permutation cannot be advanced further
866  if (n == 1) then
867  ok = .false.
868  return
869  end if
870 
871  i = n
872 
873  do
874  k = i
875  i = i - 1
876  if (p(i) < p(k)) then
877  j = n
878  do while (p(i) >= p(j))
879  j = j - 1
880  end do
881  call swap(p(i), p(j))
882  call reverse(p(k:n))
883  ok = .true.
884  return
885  else if (i == 1) then
886  ok = .false.
887  return
888  end if
889  end do
890 
891  end function next_permutation
892 
893 
900  subroutine swap (a, b)
901 
902  integer, intent(inout) :: a, b
903  integer :: c
904 
905  c = a
906  a = b
907  b = c
908 
909  end subroutine swap
910 
911 
918  subroutine reverse (a)
919 
920  integer, intent(inout) :: a(:)
921  integer :: i, n
922 
923  n = size(a)
924 
925  do i = 1, n/2
926  call swap(a(i), a(n + 1 - i))
927  end do
928 
929  end subroutine reverse
930 
931 
946  subroutine kahan_add (X, dX, err)
947 
948  complex(wp), intent(inout) :: X, err
949  complex(wp), intent(in) :: dX
950 
951  complex(wp) :: Y, Z
952 
953  y = dx - err
954  z = x + y
955  err = (z - x) - y ! the parenthesis must be obeyed, otherwise we get rubbish
956  x = z
957 
958  end subroutine kahan_add
959 
960 
990  real(wp) function beta_contraction_tensor (j, n, p, li, mi, qi, lj, mj, qj) result (t)
991 
992  use dipelm_special_functions, only: threej
993  use multidip_params, only: rone
994 
995  integer, intent(in) :: j, n, p(n), li, mi, qi(n), lj, mj, qj(n)
996  integer :: mu, l(n + 1), lp(n + 1), a(n + 1), ap(n + 1), b(n + 1), bp(n + 1)
997  real(wp) :: i, q
998 
999  l(1) = li; l(2:) = 1
1000  lp(1) = lj; lp(2:) = 1
1001 
1002  b(1) = -mi; b(2:) = qi
1003  bp(1) = -mj; bp(2:) = qj
1004 
1005  t = 0
1006 
1007  do mu = -li, li
1008 
1009  a(1) = -mu; a(2:) = p
1010  ap(1) = -mu; ap(2:) = p
1011 
1012  i = (-1)**(mi + mj) * wigner_d_multiint(n + 1, l, a, b, lp, ap, bp)
1013  q = (-1)**mu * (2*j + 1) * sqrt((2*li + rone)*(2*lj + rone)) &
1014  * threej(2*li, 0, 2*lj, 0, 2*j, 0) * threej(2*li, 2*mu, 2*lj, -2*mu, 2*j, 0)
1015 
1016  t = t + i*q
1017 
1018  end do
1019 
1020  end function beta_contraction_tensor
1021 
1022 
1052  recursive real(wp) function wigner_d_multiint (n, l, a, b, lp, ap, bp) result (K)
1053 
1054  use dipelm_special_functions, only: threej
1055  use multidip_params, only: rone
1056 
1057  integer, intent(in) :: n
1058  integer, intent(in) :: l(n), a(n), b(n), lp(n), ap(n), bp(n)
1059 
1060  integer :: u(n - 1), v(n - 1), up(n - 1), vp(n - 1), j(n - 1), jp(n - 1), j1, jp1
1061  real(wp) :: wa, wb, wap, wbp, w
1062 
1063  k = 0
1064 
1065  ! orthogonality relation
1066  if (n == 1) then
1067  if (l(1) == lp(1) .and. a(1) == ap(1) .and. b(1) == bp(1)) k = 1 / (2*l(1) + rone)
1068  return
1069  end if
1070 
1071  u(1) = a(1) + a(2); u(2:) = a(3:)
1072  v(1) = b(1) + b(2); v(2:) = b(3:)
1073 
1074  up(1) = ap(1) + ap(2); up(2:) = ap(3:)
1075  vp(1) = bp(1) + bp(2); vp(2:) = bp(3:)
1076 
1077  j(2:) = l(3:)
1078  jp(2:) = lp(3:)
1079 
1080  ! recursion: couple the first two angular momenta (both primed and unprimed)
1081  do j1 = max(abs(u(1)), max(abs(v(1)), abs(l(1) - l(2)))), l(1) + l(2)
1082  do jp1 = max(abs(up(1)), max(abs(vp(1)), abs(lp(1) - lp(2)))), lp(1) + lp(2)
1083 
1084  j(1) = j1
1085  jp(1) = jp1
1086 
1087  wa = threej(2*l(1), 2*a(1), 2*l(2), 2*a(2), 2*j(1), -2*u(1))
1088  wb = threej(2*l(1), 2*b(1), 2*l(2), 2*b(2), 2*j(1), -2*v(1))
1089  wap = threej(2*lp(1), 2*ap(1), 2*lp(2), 2*ap(2), 2*jp(1), -2*up(1))
1090  wbp = threej(2*lp(1), 2*bp(1), 2*lp(2), 2*bp(2), 2*jp(1), -2*vp(1))
1091  w = wigner_d_multiint(n - 1, j, u, v, jp, up, vp)
1092  k = k + (-1)**(u(1) - v(1) + up(1) - vp(1)) * (2*j1 + 1) * (2*jp1 + 1) * wa * wap * wb * wbp * w
1093 
1094  end do
1095  end do
1096 
1097  end function wigner_d_multiint
1098 
1122  real(wp) function beta_2p_arb_pol_sph_harm (lbig, mbig, n, pb, lp, mp, qb, pa, l, m, qa) result (t)
1123 
1124  use dipelm_special_functions, only: threej
1125  use dipelm_defs, only: pi
1126  use multidip_params, only: rone
1127 
1128  integer, intent(in) :: lbig, mbig, n, pa(n), pb(n), lp, mp, qa(n), l, m, qb(n)
1129  integer :: k1, k2, m1, m2, mp1, mp2, mu
1130  real(wp) :: i, i_el, fac
1131 
1132  if (n /= 2) then
1133  print *,'Not implemented for orders other than 2', n
1134  stop 1
1135  endif
1136 
1137  mp1 = -(-pa(1) + pb(1))
1138  mp2 = -(-pa(2) + pb(2))
1139  t = 0
1140 
1141  ! selection rule from the photon-electron couplings
1142  if ( mbig /= -(mp1 + mp2) ) return
1143 
1144  if (mbig == 0) then
1145  ! to be used when the spherical harmonic Y_{L,0} is expressed as sqrt((2*L+1)/(4*pi))*P_{L} and the cross section as: 1/(4*pi)*\sum_{L}b_{L}P_{L}
1146  fac = sqrt((2*l + rone)*(2*lp + rone))*(2*lbig + rone)
1147  else
1148  !to be used in all other cases when the cross section is expressed as: \sum_{L}b_{LM}Y_{L,M}^{*}
1149  fac = sqrt((2*l + rone)*(2*lp + rone)*(2*lbig + rone) / (4*pi))
1150  endif
1151 
1152  ! electron-related couplings
1153  mu = -(m - mp)
1154  i_el = (-1)**(mp) * fac * threej(2*l, 2*m, 2*lp, -2*mp, 2*lbig, 2*mu) * threej(2*l, 0, 2*lp, 0, 2*lbig, 0)
1155 
1156  do k1 = 0, 2
1157  do k2 = 0, 2
1158 
1159  ! lab-frame polarization-related couplings
1160  i = (-1)**(pa(1) + pa(2)) * threej(2*1, 2*(-pa(1)), 2*1, 2*pb(1), 2*k1, 2*mp1) * &
1161  &threej(2*1, 2*(-pa(2)), 2*1, 2*pb(2), 2*k2, 2*mp2)
1162 
1163  ! photon-related couplings
1164  m1 = -(-qa(1) + qb(1))
1165  m2 = -(-qa(2) + qb(2))
1166 
1167  i = i * (2*k1 + 1) * (2*k2 + 1) * (-1)**(-qa(1)-qa(2)) * threej(2*1, 2*(-qa(1)), 2*1, 2*qb(1), 2*k1, 2*m1) * &
1168  threej(2*1, 2*(-qa(2)), 2*1, 2*qb(2), 2*k2, 2*m2)
1169 
1170  ! photon-electron couplings: Mbig = -(Mp1 + Mp2)
1171  i = i * i_el * threej(2*k1, 2*mp1, 2*k2, 2*mp2, 2*lbig, 2*mbig) * threej(2*k1, 2*m1, 2*k2, 2*m2, 2*lbig, 2*mu)
1172 
1173  t = t + i
1174 
1175  enddo !K2
1176  enddo !K1
1177 
1178  end function beta_2p_arb_pol_sph_harm
1179 
1180 
1190  real(wp) function beta_2p_demekhin (l, p1, p2, li, mi, q1i, q2i, lj, mj, q1j, q2j) result (b)
1191 
1192  use dipelm_special_functions, only: threej
1193  use multidip_params, only: rone
1194 
1195  integer, intent(in) :: l, p1, p2, li, mi, lj, mj, q1i, q1j, q2i, q2j
1196 
1197  integer :: m_l, j, m_j, k, m_k
1198  real(wp) :: w(6)
1199 
1200  b = 0
1201  m_l = -(mi - mj)
1202 
1203  do j = 0, 2
1204  do m_j = -j, +j
1205  do k = 0, 2
1206  do m_k = -k, +k
1207  w(1) = threej(2*1, 2*p1, 2*1, -2*p1, 2*j, 0)
1208  w(2) = threej(2*1, 2*q1i, 2*1, -2*q1j, 2*j, -2*m_j)
1209  w(3) = threej(2*1, 2*q2i, 2*1, -2*q2j, 2*k, -2*m_k)
1210  w(4) = threej(2*1, 2*p2, 2*1, -2*p2, 2*k, 0)
1211  w(5) = threej(2*j, 2*m_j, 2*k, 2*m_k, 2*l, 2*m_l)
1212  w(6) = threej(2*j, 0, 2*k, 0, 2*l, 0)
1213  b = b + (-1)**(q1j + q2j) * (2*j + 1) * (2*k + 1) * product(w(1:6))
1214  end do
1215  end do
1216  end do
1217  end do
1218 
1219  w(1) = threej(2*li, 0, 2*lj, 0, 2*l, 0)
1220  w(2) = threej(2*li, -2*mi, 2*lj, 2*mj, 2*l, -2*m_l)
1221 
1222  b = b * (-1)**mi * (2*l + 1) * sqrt((2*li + rone)*(2*lj + rone)) * product(w(1:2))
1223 
1224  end function beta_2p_demekhin
1225 
1226 
1248  real(wp) recursive function cartesian_vector_component_product_average (q) result (a)
1249 
1250  integer, intent(in) :: q(:)
1251  integer :: i, n, iq(size(q))
1252 
1253  n = size(q)
1254 
1255  ! set up an index array
1256  do i = 1, n
1257  iq(i) = i
1258  end do
1259 
1260  if (n == 0) then
1261  ! trivial integral of unity
1262  a = 1
1263  else if (mod(n, 2) == 1) then
1264  ! for odd number of indices the integral is zero
1265  a = 0
1266  else
1267  ! collect contributions from all permutations
1268  a = 0
1269  do i = 2, n
1270  if (q(1) == q(i)) then
1271  a = a + cartesian_vector_component_product_average(pack(q, iq /= 1 .and. iq /= i))
1272  end if
1273  end do
1274  end if
1275 
1276  ! add the normalization factor
1277  if (a /= 0) then
1278  a = a / (n + 1)
1279  end if
1280 
1282 
1283 end module multidip_special
Hard-coded parameters of MULTIDIP.
real(wp), parameter rone
complex(wp), parameter cone
real(wp), parameter rzero
integer, parameter ntermsasy
Number of terms in expansion of the Coulomb-Hankel functions.
complex(wp), parameter czero
Special functions and objects used by MULTIDIP.
subroutine diagonalize_symm_matrix(M, eigs, eigv, check)
Diagonalize a real symmetric matrix.
real(wp) function beta_2p_arb_pol_sph_harm(Lbig, Mbig, n, pB, lp, mp, qB, pA, l, m, qA)
Two-photon asymmetry parameter for the arbitrary polarized case.
recursive real(wp) function wigner_d_multiint(n, l, a, b, lp, ap, bp)
Orientation averaging.
subroutine solve_complex_system(n, A, X, Y)
Solve system of equations with complex matrix.
subroutine kahan_add(X, dX, err)
Compensated summation.
recursive complex(wp) function complex_gamma(l, x)
Complex Gamma function.
subroutine coul_ukrmol(Z, l, Ek, r, F, Fp, G, Gp)
Coulomb functions (UKRmol)
complex(wp) function coulh(Z, s, l, Ek, r)
Coulomb-Hankel function.
subroutine coul(Z, l, Ek, r, F, Fp, G, Gp)
Coulomb functions.
complex(wp) function coulh_asy(Z, s, l, Ek, r)
Coulomb-Hankel function (asymptotic form)
subroutine calculate_t_matrix(K, T, nopen)
Calculate T-matrix from K-matrix.
subroutine scatak(rmatr, eig, etot, w, Ek, l, Km, Ak)
Photoionization coefficient.
subroutine calculate_s_matrix(T, S, nopen)
Calculate S-matrix from T-matrix.
real(wp) recursive function cartesian_vector_component_product_average(q)
Return Cartesian invariant.
subroutine invert_matrix(T)
Invert a complex matrix.
subroutine coul_gsl(Z, l, Ek, r, F, Fp, G, Gp)
Coulomb functions (GSL)
real(wp) function beta_contraction_tensor(J, n, p, li, mi, qi, lj, mj, qj)
Angular part of the beta parameters.
subroutine swap(a, b)
Exchange value of two integers.
subroutine calculate_r_matrix(nchan, nstat, wmat, eig, Etot, Rmat)
Calculate scattering R-matrix.
subroutine reverse(a)
Reverse order of elements in array.
real(wp) function cphase(Z, l, k)
Coulomb phase.
real(wp) function beta_2p_demekhin(L, p1, p2, li, mi, q1i, q2i, lj, mj, q1j, q2j)
Two-photon asymmetry parameter.
logical function next_permutation(p)
Construct or advance permutation.