Multidip 1.0
Multi-photon matrix elements
Loading...
Searching...
No Matches
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!
22!> \brief Special functions and objects used by MULTIDIP
23!> \author J Benda
24!> \date 2020
25!>
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 !> Derived type used by GSL for returning results
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
219contains
220
221 !> \brief Calculate scattering R-matrix
222 !> \authors J Benda
223 !> \date 2023
224 !>
225 !> R-matrix is calculated from boundary amplitudes and R-matrix poles provided using the formula
226 !> \f[
227 !> R_{uv}(E) = \sum_{j} w_{uj}(a) \frac{1}{E_j - E} w_{vj}(a) \,.
228 !> \f]
229 !>
230 !> \param[in] nchan Number of partial wave channels in this symmetry.
231 !> \param[in] nstat Number of inner region states in this symmetry.
232 !> \param[in] wmat Boundary amplitudes for this symmetry.
233 !> \param[in] eig R-matrix poles for this symmetry.
234 !> \param[in] Etot Total energy of the target + electron system.
235 !> \param[inout] Rmat R-matrix to calculate.
236 !>
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
263 !> \brief Calculate T-matrix from K-matrix
264 !> \authors J Benda
265 !> \date 2024
266 !>
267 !> Use real algebra to obtain the scattering T-matrix defined as
268 !> \f[
269 !> T = S - 1 = 2iK (1 - iK)^{-1} = 2i (1 - iK)^{-1} K = -2K (1 + K^2)^{-1} K + 2i (1 + K^2)^{-1} K
270 !> \f]
271 !> Only the open-open sub-block of the K-matrix is used.
272 !>
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, 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
330 !> \brief Calculate S-matrix from T-matrix
331 !> \author J Benda
332 !> \date 2020 - 2024
333 !>
334 !> Obtain the S-matrix from the definition formula
335 !> \f[
336 !> S = (1 + iK) (1 - iK)^{-1} = 1 + T
337 !> \f]
338 !>
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 :: 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
358 !> \brief Photoionization coefficient
359 !> \author J Benda
360 !> \date 2020
361 !>
362 !> Evaluates the wave function coefficient Ak for the final stationary photoionization wave.
363 !>
364 !> \param[in] rmatr R-matrix radius for Coulomb wave matching
365 !> \param[in] eig Inner eigenenergies (R-matrix poles) for this irreducible representation
366 !> \param[in] etot Total energy of the system
367 !> \param[in] w Boundary amplitudes
368 !> \param[in] Ek Photoelectron kinetic energies in *all* channels (open and closed)
369 !> \param[in] l Photoelectron angular momentum in *all* channels (open and closed)
370 !> \param[in] Km K-matrix
371 !> \param[inout] Ak Wave function coefficients, needs to be allocated to neig x nopen and only that part will be written
372 !>
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, 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
433 !> \brief Coulomb phase
434 !> \author J Benda
435 !> \date 2020 - 2023
436 !>
437 !> Return the Coulomb phase, arg Gamma(l + 1 - iZ/k). Uses GSL or the UKRmol-out
438 !> library, depending on the configuration.
439 !>
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
460 !> \brief Complex Gamma function
461 !> \author J Benda
462 !> \date 2021 - 2024
463 !>
464 !> Evaluate the complex Gamma function Γ(l + 1 + i*x), where l is integer.
465 !>
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
506 !> \brief Coulomb functions
507 !> \author J Benda
508 !> \date 2020 - 2023
509 !>
510 !> Evaluate the Coulomb wave (regular, irregular and derivatives). Uses GSL or the UKRmol-out
511 !> library, depending on the configuration. For negative energies, evaluates the exponentially
512 !> decreasing solution (into G and Gp) obtained from the Whittaker function (if charged) or
513 !> from solution of the appropriate equation (if neutral).
514 !>
515 !> The derivatives returned are with respect to \f$ r \f$ already, so they should not be multiplied
516 !> by the additional factor of \f$ k \f$.
517 !>
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
531 !> \brief Coulomb-Hankel function
532 !> \author J Benda
533 !> \date 2021 - 2023
534 !>
535 !> See \ref coul for explanation of the arguments.
536 !>
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
551 !> \brief Coulomb-Hankel function (asymptotic form)
552 !> \author J Benda
553 !> \date 2021 - 2023
554 !>
555 !> Implements the asymptotic formula for Coulomb-Hankel function, DLMF §33.11.1.
556 !> The number of terms is centrally controlled by a parameter in module multidip_params
557 !> to be consistent with what is used in the integration routines.
558 !>
559 !> See \ref coul for explanation of the arguments.
560 !>
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
603 !> \brief Coulomb functions (GSL)
604 !> \author J Benda
605 !> \date 2020 - 2023
606 !>
607 !> Coulomb functions (positive- and negative-energy) calculated using GSL. The derivative is with respect to \f$ r \f$
608 !> in the argument \f$ kr \f$, so the obtained derivatives contain an additional multiplication factor \f$ k \f$ compared to
609 !> the standard normalization of the Coulomb functions.
610 !>
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 (r <= 0) then
622 f = 0; fp = 0
623 g = 0; gp = 0
624 else if (ek > 0) then
625 ! positive-energy solution
626 k = sqrt(2*ek)
627 rho = k*r
628 eta = -z/k
629 lc = l
630 err = gsl_sf_coulomb_wave_fg_e(eta, rho, lc, zero, resf, resfp, resg, resgp, expf, expg)
631 f = resf % val
632 fp = resfp % val * k
633 g = resg % val
634 gp = resgp % val * k
635 else
636 ! negative-energy solution, Whittaker function W (WARNING: charged only)
637 k = sqrt(-2*ek)
638 a = l + 1 - z/k
639 b = 2*l + 2
640 x = 2*k*r
641 u = gsl_sf_hyperg_u(a, b, x)
642 up = -2*k*a * gsl_sf_hyperg_u(a + 1, b + 1, x) ! DLMF §13.3.22
643 f = 0
644 fp = 0
645 g = exp(-x/2) * x**(l + 1) * u ! DLMF §13.14.3
646 gp = exp(-x/2) * x**(l + 1) * (-k * u + (l + 1)/r * u + up)
647 end if
648#else
649 f = 0; fp = 0
650 g = 0; gp = 0
651#endif
652 end subroutine coul_gsl
653
654
655 !> \brief Coulomb functions (UKRmol)
656 !> \author J Benda
657 !> \date 2020 - 2023
658 !>
659 !> Coulomb functions (positive- and negative-energy) calculated using UKRmol-out. The derivative is with respect to \f$ r \f$
660 !> in the argument \f$ kr \f$, so the obtained derivatives contain an additional multiplication factor \f$ k \f$ compared to
661 !> the standard normalization of the Coulomb functions.
662 !>
663 subroutine coul_ukrmol (Z, l, Ek, r, F, Fp, G, Gp)
664
665 integer, intent(in) :: l
666 real(wp), intent(in) :: Z, Ek, r
667 real(wp), intent(inout) :: F, Fp, G, Gp
668 integer :: ifail, mode = 1, kfn = 0, nterms, iwrite = 0
669 real(wp) :: fc(l + 1), gc(l + 1), fcp(l + 1), gcp(l + 1), lc, efx, fnorm, acc = 1e-10_wp, k
670
671 lc = l
672 if (ek > 0) then
673 ! positive-energy solution
674 k = sqrt(2*ek)
675 call coulfg(k*r, -z/k, lc, lc, fc, gc, fcp, gcp, mode, kfn, ifail)
676 f = fc(l + 1)
677 g = gc(l + 1)
678 fp = fcp(l + 1) * k
679 gp = gcp(l + 1) * k
680 else
681 ! negative energy solution (charged or neutral)
682 if (z /= 0) then
683 call couln(l, z, 2*ek, r, g, gp, acc, efx, ifail, nterms, fnorm)
684 else
685 call decay(2*ek, l, r, g, gp, iwrite)
686 end if
687 f = 0
688 fp = 0
689 end if
690
691 end subroutine coul_ukrmol
692
693
694 !> \brief Diagonalize a real symmetric matrix
695 !> \authors J Benda
696 !> \date 2023
697 !>
698 !> Obtain eigenvectors and eigenvalues of a real symmetric matrix. The phase of the eigenvectors is fixed so that
699 !> the element of each eigenvectors largest in magnitude is positive.
700 !>
701 !> \param[in] M Matrix to diagonalize (N × N)
702 !> \param[inout] eigs On exit the eigenvalues (N)
703 !> \param[inout] eigv On exit the eigenvectors (N × N)
704 !> \param[in] check Optional threshold. If positive, check that the obtained eigenvectors are orthonormal to this accuracy.
705 !>
706 subroutine diagonalize_symm_matrix (M, eigs, eigv, check)
707
708 real(wp), intent(in) :: M(:, :)
709 real(wp), intent(inout) :: eigs(:), eigv(:, :)
710 real(wp), intent(in), optional :: check
711
712 integer(blasint) :: i, n, info, lwork
713 real(wp), allocatable :: work(:), tmp(:, :)
714 real(wp) :: diag, offdiag
715
716 n = size(eigs)
717 eigv = m
718 allocate (work(1))
719 call dsyev('V', 'U', n, eigv, n, eigs, work, -1_blasint, info)
720
721 if (info /= 0) then
722 write (error_unit, '(a,i0,a)') 'Error ', info, ' when preparing matrix diagonalization'
723 stop 1
724 end if
725
726 lwork = work(1)
727 deallocate (work)
728 allocate (work(lwork))
729 call dsyev('V', 'U', n, eigv, n, eigs, work, lwork, info)
730
731 if (info /= 0) then
732 write (error_unit, '(a,i0,a)') 'Error ', info, ' when diagonalizing matrix'
733 stop 1
734 end if
735
736 ! fix phase of the eigenvectors (element largest in magnitude has to be positive)
737 do i = 1, n
738 if (eigv(maxloc(abs(eigv(:, i)), 1), i) < 0) then
739 eigv(:, i) = -eigv(:, i)
740 end if
741 end do
742
743 ! verify that the eigenvector matrix is orthogonal
744 if (present(check)) then
745 if (check > 0) then
746 allocate (tmp(n, n))
747 call dgemm('N', 'T', n, n, n, 1._wp, eigv, n, eigv, n, 0._wp, tmp, n)
748 do i = 1, n
749 diag = tmp(i, i)
750 offdiag = sqrt(sum(abs(tmp(:, i))**2) - diag**2)
751 if (abs(diag - 1) > check .or. abs(offdiag) > check) then
752 write (error_unit, '(a,i0,2e25.15)') 'WARNING: Orthogonality error in symmetric diagonalization ', &
753 i, diag, offdiag
754 stop 1
755 end if
756 end do
757 end if
758 end if
759
760 end subroutine diagonalize_symm_matrix
761
762
763 !> \brief Invert a complex matrix
764 !> \author J Benda
765 !> \date 2020
766 !>
767 !> Calculate inverse of a complex matrix. Use the standard LAPACK decompose+solve sequence.
768 !>
769 subroutine invert_matrix (T)
770
771 complex(wp), allocatable, intent(inout) :: T(:, :)
772
773 complex(wp), allocatable :: work(:)
774 complex(wp) :: nwork(1)
775
776 integer(blasint), allocatable :: ipiv(:)
777 integer(blasint) :: m, info, lwork
778
779 m = size(t, 1)
780
781 ! calculate LU decomposition
782 allocate (ipiv(m))
783 call zgetrf(m, m, t, m, ipiv, info)
784
785 ! query for workspace size and allocate memory
786 lwork = -1
787 call zgetri(m, t, m, ipiv, nwork, lwork, info)
788 lwork = int(nwork(1))
789 allocate (work(lwork))
790
791 ! compute the inverse
792 call zgetri(m, t, m, ipiv, work, lwork, info)
793
794 end subroutine invert_matrix
795
796
797 !> \brief Solve system of equations with complex matrix
798 !> \author J Benda
799 !> \date 2020
800 !>
801 !> The matrix A is complex. The columns of matrices X and Y correspond to real and imaginary
802 !> part of the right-hand side and of the solution, respectively.
803 !>
804 subroutine solve_complex_system (n, A, X, Y)
805
806 complex(wp), allocatable, intent(inout) :: A(:, :)
807 real(wp), allocatable, intent(inout) :: X(:, :), Y(:, :)
808 integer, intent(in) :: n
809
810 integer(blasint) :: m, info, nrhs, lda
811 integer(blasint), allocatable :: ipiv(:)
812 complex(wp), allocatable :: XX(:)
813
814 allocate (ipiv(n))
815
816 ! calculate LU decomposition
817 m = n
818 lda = size(a, 1)
819 call zgetrf(m, m, a, lda, ipiv, info)
820
821 ! combine real and imaginary part of the right-hand side
822 xx = cmplx(x(1:n, 1), x(1:n, 2), wp)
823
824 ! solve the equation
825 nrhs = 1
826 call zgetrs('N', m, nrhs, a, lda, ipiv, xx, m, info)
827
828 y(1:n, 1) = real(xx, wp)
829 y(1:n, 2) = aimag(xx)
830
831 end subroutine solve_complex_system
832
833
834 !> \brief Construct or advance permutation
835 !> \author J Benda
836 !> \date 2020
837 !>
838 !> If the given integer array contains a negative element, fill it with identical permutation (i.e.
839 !> the sequence 1, 2, ..., N) and return TRUE. Otherwise attempt to generate the "next" permutation
840 !> of the N values in the manner compatible with C++ `std::next_permutation` (lexicographically ordered
841 !> sequences). When no further permutation is possible, return FALSE.
842 !>
843 !> The algorithm is shamelessly copied from the source of GCC's libstdc++ library and (except for the
844 !> added initialization option) faithfully mimics the behaviour of the built-on C++ function `std::next_permutation`.
845 !>
846 logical function next_permutation (p) result (ok)
847
848 integer, intent(inout) :: p(:)
849 integer :: i, j, k, n
850
851 n = size(p)
852
853 ! no permutation in empty array
854 if (n == 0) then
855 ok = .false.
856 return
857 end if
858
859 ! initialize a new permutation
860 if (any(p < 1)) then
861 do i = 1, n
862 p(i) = i
863 end do
864 ok = .true.
865 return
866 end if
867
868 ! one-element permutation cannot be advanced further
869 if (n == 1) then
870 ok = .false.
871 return
872 end if
873
874 i = n
875
876 do
877 k = i
878 i = i - 1
879 if (p(i) < p(k)) then
880 j = n
881 do while (p(i) >= p(j))
882 j = j - 1
883 end do
884 call swap(p(i), p(j))
885 call reverse(p(k:n))
886 ok = .true.
887 return
888 else if (i == 1) then
889 ok = .false.
890 return
891 end if
892 end do
893
894 end function next_permutation
895
896
897 !> \brief Exchange value of two integers
898 !> \author J Benda
899 !> \date 2020
900 !>
901 !> This subroutine mimics the behaviour of the built-in C++ function std::swap.
902 !>
903 subroutine swap (a, b)
904
905 integer, intent(inout) :: a, b
906 integer :: c
907
908 c = a
909 a = b
910 b = c
911
912 end subroutine swap
913
914
915 !> \brief Reverse order of elements in array
916 !> \author J Benda
917 !> \date 2020
918 !>
919 !> This subroutine mimics the behaviour of the built-in C++ function `std::reverse`.
920 !>
921 subroutine reverse (a)
922
923 integer, intent(inout) :: a(:)
924 integer :: i, n
925
926 n = size(a)
927
928 do i = 1, n/2
929 call swap(a(i), a(n + 1 - i))
930 end do
931
932 end subroutine reverse
933
934
935 !> \brief Compensated summation
936 !> \author J Benda
937 !> \date 2020
938 !>
939 !> Add dX to X, keep track of numerical error. Uses Kahan's algorithm. This subroutine is in infinite
940 !> precision equivalent to just
941 !> ```
942 !> X = X + dX
943 !> err = 0
944 !> ```
945 !> but in the finite precision arithmetic it compensates the running numerical error. It mustn't be
946 !> optimized away by the compiler! Flags like `-ffast-math` or `-Ofast` are detrimental here. Common
947 !> optimization flags like `-O2` or `-O3` should be safe (but it may depend on the compiler).
948 !>
949 subroutine kahan_add (X, dX, err)
950
951 complex(wp), intent(inout) :: X, err
952 complex(wp), intent(in) :: dX
953
954 complex(wp) :: Y, Z
955
956 y = dx - err
957 z = x + y
958 err = (z - x) - y ! the parenthesis must be obeyed, otherwise we get rubbish
959 x = z
960
961 end subroutine kahan_add
962
963
964 !> \brief Angular part of the beta parameters
965 !> \author J Benda
966 !> \date 2020
967 !>
968 !> Evaluates the contraction coefficient \f$ T_{m p_1 q_1 q_1'\dots p_n q_n q_n'}^{Jll'} \f$ in
969 !> \f[
970 !> \frac{\mathrm{d}\sigma^{(p_1\dots p_n)}}{\mathrm{d}\Omega} = \frac{1}{4\pi} \sum_{J} b_J^{(p_1\dots p_n)} P_J(\cos\theta)
971 !> = \frac{1}{4\pi} \sum_{Jlml'm'\atop q_1 q_1' \dots q_n q_n'}
972 !> M_{mq_1\dots q_n}^{(l)} M_{m'q_1'\dots q_n'}^{(l')*} T_{m m', p_1 q_1 q_1'\dots p_n q_n q_n'}^{Jll'} P_J(\cos\theta),
973 !> \f]
974 !> which has the following explicit form:
975 !> \f[
976 !> T_{m m', p_1 q_1 q_1'\dots p_n q_n q_n'}^{Jll'} = \sum_{\mu} (-1)^{\mu} (2J + 1) \sqrt{(2l + 1)(2l' + 1)}
977 !> \left(\begin{matrix} l & l' & J \\ 0 & 0 & 0 \end{matrix}\right)
978 !> \left(\begin{matrix} l & l' & J \\ \mu & -\mu & 0 \end{matrix}\right)
979 !> \frac{1}{8\pi^2} \int D_{\mu m}^{(l)} D_{\mu m'}^{(l')*} D_{p_1 q_1}^{(1)*} D_{p_1 q_1'}^{(1)} \dots
980 !> D_{p_n q_n}^{(1)*} D_{p_n q_n}^{(1)} \mathrm{d}\hat{R} .
981 !> \f]
982 !> The real averaging integral over orientations of the molecule is re-expressed as
983 !> \f[
984 !> (-1)^{m + m'}
985 !> \frac{1}{8\pi^2} \int D_{-\mu, -m}^{(l)*} D_{-\mu, -m'}^{(l')} D_{p_1 q_1}^{(1)*} D_{p_1 q_1'}^{(1)} \dots
986 !> D_{p_n q_n}^{(1)*} D_{p_n q_n}^{(1)} \mathrm{d}\hat{R}
987 !> \f]
988 !> and then calculated in \ref wigner_D_multiint.
989 !>
990 !> \note In the present implementation, all laboratory-frame polarisations \f$ p_i \f$ are considered equal to zero, i.e.
991 !> the field is linearly polarized.
992 !>
993 real(wp) function beta_contraction_tensor (j, n, p, li, mi, qi, lj, mj, qj) result (t)
994
995 use dipelm_special_functions, only: threej
996 use multidip_params, only: rone
997
998 integer, intent(in) :: j, n, p(n), li, mi, qi(n), lj, mj, qj(n)
999 integer :: mu, l(n + 1), lp(n + 1), a(n + 1), ap(n + 1), b(n + 1), bp(n + 1)
1000 real(wp) :: i, q
1001
1002 l(1) = li; l(2:) = 1
1003 lp(1) = lj; lp(2:) = 1
1004
1005 b(1) = -mi; b(2:) = qi
1006 bp(1) = -mj; bp(2:) = qj
1007
1008 t = 0
1009
1010 do mu = -li, li
1011
1012 a(1) = -mu; a(2:) = p
1013 ap(1) = -mu; ap(2:) = p
1014
1015 i = (-1)**(mi + mj) * wigner_d_multiint(n + 1, l, a, b, lp, ap, bp)
1016 q = (-1)**mu * (2*j + 1) * sqrt((2*li + rone)*(2*lj + rone)) &
1017 * threej(2*li, 0, 2*lj, 0, 2*j, 0) * threej(2*li, 2*mu, 2*lj, -2*mu, 2*j, 0)
1018
1019 t = t + i*q
1020
1021 end do
1022
1023 end function beta_contraction_tensor
1024
1025
1026 !> \brief Orientation averaging
1027 !> \author J Benda
1028 !> \date 2020
1029 !>
1030 !> Calculate the value of the integral
1031 !> \f[
1032 !> \frac{1}{8\pi^2} \int D_{a_1 b_1}^{(l_1)} D_{a_1' b_1'}^{(l_1')*} \dots
1033 !> D_{a_1 b_1}^{(l_n)} D_{a_n' b_n'}^{(l_n')*} \mathrm{d}\hat{R}
1034 !> \f]
1035 !> over all orientations (Euler angles) \f$ \hat{R} \f$. The calculation is done recursively using the formula
1036 !> \f[
1037 !> D_{a_1 b_1}^{(l_1)} D_{a_2 b_2}^{(l_2)} = \sum_{juv} (-1)^{u - v} (2j + 1)
1038 !> \left(\begin{matrix} l_1 & l_2 & j \\ a_1 & a_2 & -u \end{matrix}\right)
1039 !> \left(\begin{matrix} l_1 & l_2 & j \\ b_1 & b_2 & -v \end{matrix}\right)
1040 !> D_{u v}^{(j)}
1041 !> \f]
1042 !> that is applied to \f$ D_{p_1 q_1}^{(l_1)} D_{p_2 q_2}^{(l_2)} \f$ and to \f$ D_{p_1 q_1'}^{(l_1)} D_{p_2 q_2'}^{(l_2)} \f$,
1043 !> leading to the linear combination of shorter integrals
1044 !> \f[
1045 !> \frac{1}{8\pi^2} \int D_{u v}^{(j)} D_{u' v'}^{(j')*} D_{a_3 b_3}^{(l_3)} D_{a_3' b_3'}^{(l_3)*}
1046 !> \dots D_{a_n b_n}^{(l_n)} D_{a_n' b_n'}^{(l_n)*} \mathrm{d}\hat{R}
1047 !> \f]
1048 !> The recursion terminates when only the pair \f$ D_{u v}^{(j)} D_{u' v'}^{(j')*} \f$ is left,
1049 !> by means of the orthogonality relation
1050 !> \f[
1051 !> \frac{1}{8\pi^2} \int D_{u v}^{(j)} D_{u' v'}^{(j')*} \mathrm{d}\hat{R}
1052 !> = \frac{1}{2j + 1} \delta_{jj'} \delta_{uu'} \delta_{vv'} \,.
1053 !> \f]
1054 !>
1055 recursive real(wp) function wigner_d_multiint (n, l, a, b, lp, ap, bp) result (K)
1056
1057 use dipelm_special_functions, only: threej
1058 use multidip_params, only: rone
1059
1060 integer, intent(in) :: n
1061 integer, intent(in) :: l(n), a(n), b(n), lp(n), ap(n), bp(n)
1062
1063 integer :: u(n - 1), v(n - 1), up(n - 1), vp(n - 1), j(n - 1), jp(n - 1), j1, jp1
1064 real(wp) :: wa, wb, wap, wbp, w
1065
1066 k = 0
1067
1068 ! orthogonality relation
1069 if (n == 1) then
1070 if (l(1) == lp(1) .and. a(1) == ap(1) .and. b(1) == bp(1)) k = 1 / (2*l(1) + rone)
1071 return
1072 end if
1073
1074 u(1) = a(1) + a(2); u(2:) = a(3:)
1075 v(1) = b(1) + b(2); v(2:) = b(3:)
1076
1077 up(1) = ap(1) + ap(2); up(2:) = ap(3:)
1078 vp(1) = bp(1) + bp(2); vp(2:) = bp(3:)
1079
1080 j(2:) = l(3:)
1081 jp(2:) = lp(3:)
1082
1083 ! recursion: couple the first two angular momenta (both primed and unprimed)
1084 do j1 = max(abs(u(1)), max(abs(v(1)), abs(l(1) - l(2)))), l(1) + l(2)
1085 do jp1 = max(abs(up(1)), max(abs(vp(1)), abs(lp(1) - lp(2)))), lp(1) + lp(2)
1086
1087 j(1) = j1
1088 jp(1) = jp1
1089
1090 wa = threej(2*l(1), 2*a(1), 2*l(2), 2*a(2), 2*j(1), -2*u(1))
1091 wb = threej(2*l(1), 2*b(1), 2*l(2), 2*b(2), 2*j(1), -2*v(1))
1092 wap = threej(2*lp(1), 2*ap(1), 2*lp(2), 2*ap(2), 2*jp(1), -2*up(1))
1093 wbp = threej(2*lp(1), 2*bp(1), 2*lp(2), 2*bp(2), 2*jp(1), -2*vp(1))
1094 w = wigner_d_multiint(n - 1, j, u, v, jp, up, vp)
1095 k = k + (-1)**(u(1) - v(1) + up(1) - vp(1)) * (2*j1 + 1) * (2*jp1 + 1) * wa * wap * wb * wbp * w
1096
1097 end do
1098 end do
1099
1100 end function wigner_d_multiint
1101
1102 !> \brief Two-photon asymmetry parameter for the arbitrary polarized case
1103 !> \author Z Masin
1104 !> \date 2023
1105 !>
1106 !> Explicit form of the two-photon asymmetry parameter from Ertel et al, Journal of Chemical Physics, submitted, (2023).
1107 !> This routine implements the most general case when the polarizations of all four photons involved are chosen arbitrarily.
1108 !> The resulting asymmetry parameter can have a non-zero M value corresponding to a spherical harmonic Y_{L,M}^{*}.
1109 !>
1110 !> The routine uses two different conventions for the asymmetry parameters. In case of M = 0 (no net difference between
1111 !> the polarizations in the two 2-photon arms) the routine uses the Legendre polynomials P_{L} as the basis:
1112 !> \f[
1113 !> I = \frac{1}{4\pi}\sum_{L=0}^{4}b_{L}P_{L}(\cos\theta).
1114 !> \f]
1115 !> In the general case with M /= 0 the asymmetry parameters are coefficients in spherical harmonic expansion:
1116 !> \f[
1117 !> I = \sum_{L,M}\hat{b}_{L,M}Y_{L,M}^{*}(\mathbf{k}).
1118 !> \f]
1119 !> Note the conjugation of the spherical harmonic of momentum.
1120 !>
1121 !> The input for this routine differs from that for beta_2p_demekhin and beta_contraction_tensor in the choice of the
1122 !> polarizations of the photons for the first (A) and second (B) 2-photon amplitudes by means of the arrays pA and pB.
1123 !> Each of them specifies the polarizations of the first and second photons.
1124 !>
1125 real(wp) function beta_2p_arb_pol_sph_harm (lbig, mbig, n, pb, lp, mp, qb, pa, l, m, qa) result (t)
1126
1127 use dipelm_special_functions, only: threej
1128 use dipelm_defs, only: pi
1129 use multidip_params, only: rone
1130
1131 integer, intent(in) :: lbig, mbig, n, pa(n), pb(n), lp, mp, qa(n), l, m, qb(n)
1132 integer :: k1, k2, m1, m2, mp1, mp2, mu
1133 real(wp) :: i, i_el, fac
1134
1135 if (n /= 2) then
1136 print *,'Not implemented for orders other than 2', n
1137 stop 1
1138 endif
1139
1140 mp1 = -(-pa(1) + pb(1))
1141 mp2 = -(-pa(2) + pb(2))
1142 t = 0
1143
1144 ! selection rule from the photon-electron couplings
1145 if ( mbig /= -(mp1 + mp2) ) return
1146
1147 if (mbig == 0) then
1148 ! 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}
1149 fac = sqrt((2*l + rone)*(2*lp + rone))*(2*lbig + rone)
1150 else
1151 !to be used in all other cases when the cross section is expressed as: \sum_{L}b_{LM}Y_{L,M}^{*}
1152 fac = sqrt((2*l + rone)*(2*lp + rone)*(2*lbig + rone) / (4*pi))
1153 endif
1154
1155 ! electron-related couplings
1156 mu = -(m - mp)
1157 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)
1158
1159 do k1 = 0, 2
1160 do k2 = 0, 2
1161
1162 ! lab-frame polarization-related couplings
1163 i = (-1)**(pa(1) + pa(2)) * threej(2*1, 2*(-pa(1)), 2*1, 2*pb(1), 2*k1, 2*mp1) * &
1164 &threej(2*1, 2*(-pa(2)), 2*1, 2*pb(2), 2*k2, 2*mp2)
1165
1166 ! photon-related couplings
1167 m1 = -(-qa(1) + qb(1))
1168 m2 = -(-qa(2) + qb(2))
1169
1170 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) * &
1171 threej(2*1, 2*(-qa(2)), 2*1, 2*qb(2), 2*k2, 2*m2)
1172
1173 ! photon-electron couplings: Mbig = -(Mp1 + Mp2)
1174 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)
1175
1176 t = t + i
1177
1178 enddo !K2
1179 enddo !K1
1180
1181 end function beta_2p_arb_pol_sph_harm
1182
1183
1184 !> \brief Two-photon asymmetry parameter
1185 !> \author J Benda
1186 !> \date 2020
1187 !>
1188 !> Explicit form of the two-photon asymmetry parameter from Demekhin, Lagutin, Petrov, Phys. Rev. A 85 (2012) 023416.
1189 !>
1190 !> \note The explicit formula contains an apparent extra factor of (-1)^(L + lj), which is however fully absorbed
1191 !> into the phase of the wave function in the present approach.
1192 !>
1193 real(wp) function beta_2p_demekhin (l, p1, p2, li, mi, q1i, q2i, lj, mj, q1j, q2j) result (b)
1194
1195 use dipelm_special_functions, only: threej
1196 use multidip_params, only: rone
1197
1198 integer, intent(in) :: l, p1, p2, li, mi, lj, mj, q1i, q1j, q2i, q2j
1199
1200 integer :: m_l, j, m_j, k, m_k
1201 real(wp) :: w(6)
1202
1203 b = 0
1204 m_l = -(mi - mj)
1205
1206 do j = 0, 2
1207 do m_j = -j, +j
1208 do k = 0, 2
1209 do m_k = -k, +k
1210 w(1) = threej(2*1, 2*p1, 2*1, -2*p1, 2*j, 0)
1211 w(2) = threej(2*1, 2*q1i, 2*1, -2*q1j, 2*j, -2*m_j)
1212 w(3) = threej(2*1, 2*q2i, 2*1, -2*q2j, 2*k, -2*m_k)
1213 w(4) = threej(2*1, 2*p2, 2*1, -2*p2, 2*k, 0)
1214 w(5) = threej(2*j, 2*m_j, 2*k, 2*m_k, 2*l, 2*m_l)
1215 w(6) = threej(2*j, 0, 2*k, 0, 2*l, 0)
1216 b = b + (-1)**(q1j + q2j) * (2*j + 1) * (2*k + 1) * product(w(1:6))
1217 end do
1218 end do
1219 end do
1220 end do
1221
1222 w(1) = threej(2*li, 0, 2*lj, 0, 2*l, 0)
1223 w(2) = threej(2*li, -2*mi, 2*lj, 2*mj, 2*l, -2*m_l)
1224
1225 b = b * (-1)**mi * (2*l + 1) * sqrt((2*li + rone)*(2*lj + rone)) * product(w(1:2))
1226
1227 end function beta_2p_demekhin
1228
1229
1230 !> \brief Return Cartesian invariant
1231 !> \author J Benda
1232 !> \date 2022 - 2023
1233 !>
1234 !> Calculate angular average of a product of two sets of Cartesian components of a unit vector.
1235 !> The general formula is
1236 !> \f[
1237 !> \frac{1}{4\pi} \int n_{i_1} \dots n_{i_N} = \frac{1}{(N + 1)!!} {\sum_\pi}'
1238 !> \delta_{i_{\pi(1)} i_{\pi(2)}} \dots \delta_{i_{\pi(N-1)} i_{\pi(N)}} .
1239 !> \f]
1240 !> The prime denotes summation only over unique terms. Some explicit examples are:
1241 !> \f[
1242 !> \frac{1}{4\pi} \int n_i n_j = \frac{1}{3} \delta_{ij} \,,
1243 !> \f]
1244 !> where i = q(1) and j = q(2), and
1245 !> \f[
1246 !> \frac{1}{4\pi} \int n_i n_j n_k n_l =
1247 !> \frac{1}{15} (\delta_{ij}\delta_{kl} + \delta_{ik}\delta_{jl} + \delta_{il}\delta_{jk}) \,,
1248 !> \f]
1249 !> where i = q(1), j = q(2), k = q(3) and l = q(4).
1250 !>
1251 real(wp) recursive function cartesian_vector_component_product_average (q) result (a)
1252
1253 integer, intent(in) :: q(:)
1254 integer :: i, n, iq(size(q))
1255
1256 n = size(q)
1257
1258 ! set up an index array
1259 do i = 1, n
1260 iq(i) = i
1261 end do
1262
1263 if (n == 0) then
1264 ! trivial integral of unity
1265 a = 1
1266 else if (mod(n, 2) == 1) then
1267 ! for odd number of indices the integral is zero
1268 a = 0
1269 else
1270 ! collect contributions from all permutations
1271 a = 0
1272 do i = 2, n
1273 if (q(1) == q(i)) then
1274 a = a + cartesian_vector_component_product_average(pack(q, iq /= 1 .and. iq /= i))
1275 end if
1276 end do
1277 end if
1278
1279 ! add the normalization factor
1280 if (a /= 0) then
1281 a = a / (n + 1)
1282 end if
1283
1285
1286end module multidip_special
Hard-coded parameters of MULTIDIP.
real(wp), parameter pi
complex(wp), parameter imu
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.
real(wp) function beta_contraction_tensor(j, n, p, li, mi, qi, lj, mj, qj)
Angular part of the beta parameters.
subroutine diagonalize_symm_matrix(m, eigs, eigv, check)
Diagonalize a real symmetric matrix.
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)
subroutine coul_gsl(z, l, ek, r, f, fp, g, gp)
Coulomb functions (GSL)
subroutine invert_matrix(t)
Invert a complex 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.
real(wp) recursive function cartesian_vector_component_product_average(q)
Return Cartesian invariant.
real(wp) function beta_2p_demekhin(l, p1, p2, li, mi, q1i, q2i, lj, mj, q1j, q2j)
Two-photon asymmetry parameter.
real(wp) function cphase(z, l, k)
Coulomb phase.
subroutine swap(a, b)
Exchange value of two integers.
subroutine reverse(a)
Reverse order of elements in array.
subroutine coul(z, l, ek, r, f, fp, g, gp)
Coulomb functions.
logical function next_permutation(p)
Construct or advance permutation.