137 use iso_fortran_env,
only: output_unit
138 use mpi_gbl,
only: mpi_mod_start, mpi_mod_finalize
143 type(
string),
allocatable :: XUV_plus_IR_filenames(:), XUV_minus_IR_filenames(:)
144 type(
string) :: XUV_plus_IR_outdir, XUV_minus_IR_outdir, properties
146 complex(real64),
allocatable :: MM(:, :), MM0(:,:)
147 complex(real64),
allocatable :: M_XUV_plus_IR_sph(:, :, :, :), M_XUV_minus_IR_sph(:, :, :, :)
148 complex(real64),
allocatable :: M_XUV_plus_IR_xyz(:, :, :, :), M_XUV_minus_IR_xyz(:, :, :, :)
150 real(real64),
parameter :: rone = 1,
pi = 4*atan(rone)
151 real(real64),
allocatable :: theta(:), phi(:), Ek1(:), Ek2(:), prop(:, :, :), echl(:)
152 real(real64) :: polar(2), polarIR(2), axis(3), axisIR(3), wIR
154 integer,
allocatable :: target_states(:), chains1(:, :), chains2(:, :)
156 integer :: i, L, order1, order2, extend1, extend2, maxl, ntarg, nesc, maxlab, lutarg, p(nMaxPhotons)
158 character(len=200) :: str
160 if (command_argument_count() == 0)
then
165 call print_ukrmol_header(output_unit)
168 print
'(/,A,/)',
'Program RABITT: Calculation of two-photon interference amplitudes'
174 theta, phi, ek1, ek2, wir, properties, &
175 xuv_plus_ir_filenames, xuv_minus_ir_filenames, &
176 xuv_plus_ir_outdir, xuv_minus_ir_outdir))
then
181 call read_raw_multipoles(order1, order2, sph, ntarg, maxl, nesc, target_states, chains1, chains2, &
182 xuv_plus_ir_filenames, xuv_minus_ir_filenames, &
183 m_xuv_plus_ir_xyz, m_xuv_minus_ir_xyz)
184 if (nesc == 0)
return
188 if (extend1 /= 0 .or. extend2 /= 0)
then
189 print
'(/,a)',
'Error: Asymptotic extension not implemented for --spherical'
192 m_xuv_plus_ir_sph = m_xuv_plus_ir_xyz
193 m_xuv_minus_ir_sph = m_xuv_minus_ir_xyz
195 if (extend1 /= 0 .or. extend2 /= 0)
then
196 if (.not.
allocated(ek1) .or. .not.
allocated(ek2))
then
197 print
'(/,a)',
'Error: Missing photoelectron energies on the command line (--energies) for extending'
201 print
'(/,a)',
'Error: Need a positive IR energy (--ir-energy) on the command line for extending'
204 if (len_trim(properties % str) == 0)
then
205 print
'(/,a)',
'Error: Need the residual ion properties file (--properties) for extending'
208 open (newunit = lutarg, file = properties % str, action =
'read', form =
'formatted')
211 echl = echl - echl(1)
212 call extend_order(order1, m_xuv_plus_ir_xyz, chains1, extend1, ek1, wir, &
213 target_states, echl, prop, maxl, xuv_plus_ir_outdir)
214 call extend_order(order2, m_xuv_minus_ir_xyz, chains2, extend2, ek2, wir, &
215 target_states, echl, prop, maxl, xuv_minus_ir_outdir)
217 allocate (m_xuv_plus_ir_sph, mold = m_xuv_plus_ir_xyz)
218 allocate (m_xuv_minus_ir_sph, mold = m_xuv_minus_ir_xyz)
224 allocate (mm(2 + ntarg, nesc), mm0(2 + ntarg, nesc))
226 do l = 0, min(maxlab, order1 + abs(extend1) + order2 + abs(extend2))
228 str =
'rabitt-signal-L'
231 if (l == 0 .and. .not. sph)
then
233 m_xuv_plus_ir_xyz, m_xuv_minus_ir_xyz)
239 m_xuv_plus_ir_sph, m_xuv_minus_ir_sph, p)
246 where (mm0(i, :) /= 0)
247 mm(i,:) = mm(i,:) / mm0(i,:)
253 str =
'rabitt-beta-L'
260 polar = polar *
pi / 180
261 polarir = polarir *
pi / 180
262 axis = [ sin(polar(1))*cos(polar(2)), sin(polar(1))*sin(polar(2)), cos(polar(1)) ]
263 axisir = [ sin(polarir(1))*cos(polarir(2)), sin(polarir(1))*sin(polarir(2)), cos(polarir(1)) ]
265 m_xuv_plus_ir_xyz, m_xuv_minus_ir_xyz, axis, axisir, theta, phi)
268 print
'(/,A)',
'Done.'
270 call mpi_mod_finalize
300 logical function process_command_line (ord1, ord2, ext1, ext2, sph, maxlab, polar, polarIR, theta, phi, Ek1, Ek2, wIR, &
301 properties, XUV_plus_IR_filenames, XUV_minus_IR_filenames, XUV_plus_IR_outdir, &
304 integer,
intent(out) :: ord1, ord2, ext1, ext2, maxlab
305 real(real64),
intent(out) :: polar(2), polarir(2), wir
306 logical,
intent(out) :: sph
308 real(real64),
allocatable,
intent(inout) :: theta(:), phi(:), ek1(:), ek2(:)
309 real(real64),
allocatable :: real_array(:)
311 type(
string),
allocatable,
intent(inout) :: xuv_plus_ir_filenames(:), xuv_minus_ir_filenames(:)
312 type(
string),
intent(inout) :: xuv_plus_ir_outdir, xuv_minus_ir_outdir, properties
313 type(
string),
allocatable :: string_array(:)
315 character(len=8192) :: arg, filenames(2)
317 integer :: iarg, narg, basis, n, ifile, stat, u
319 narg = command_argument_count()
332 main_loop:
do while (iarg <= narg)
334 call get_command_argument(iarg, arg)
336 select case (trim(arg))
343 case (
'--one-photon')
347 case (
'--two-photon')
353 call get_command_argument(iarg, arg)
356 call get_command_argument(iarg, arg)
361 call get_command_argument(iarg, arg)
364 call get_command_argument(iarg, arg)
375 call get_command_argument(iarg, arg)
380 call get_command_argument(iarg, arg)
381 read (arg, *) polar(1)
383 call get_command_argument(iarg, arg)
384 read (arg, *) polar(2)
389 call get_command_argument(iarg, arg)
390 read (arg, *) polarir(1)
392 call get_command_argument(iarg, arg)
393 read (arg, *) polarir(2)
397 do while (iarg <= narg)
398 call get_command_argument(iarg, arg)
399 if (arg(1:2) ==
'--') cycle main_loop
401 if (
allocated(theta)) n =
size(theta)
402 allocate (real_array(n + 1))
403 if (
allocated(theta)) real_array(1:n) = theta(1:n)
404 call move_alloc(real_array, theta)
405 read (arg, *) theta(n + 1)
411 do while (iarg <= narg)
412 call get_command_argument(iarg, arg)
413 if (arg(1:2) ==
'--') cycle main_loop
415 if (
allocated(phi)) n =
size(phi)
416 allocate (real_array(n + 1))
417 if (
allocated(phi)) real_array(1:n) = phi(1:n)
418 call move_alloc(real_array, phi)
419 read (arg, *) phi(n + 1)
425 call get_command_argument(iarg, arg)
428 call get_command_argument(iarg, arg)
433 call get_command_argument(iarg, arg)
436 case (
'--xuv-plus-ir',
'--xuv+ir')
438 call get_command_argument(iarg, filenames(1))
440 case (
'--xuv-minus-ir',
'--xuv-ir')
442 call get_command_argument(iarg, filenames(2))
446 call get_command_argument(iarg, filenames(1))
448 call get_command_argument(iarg, filenames(2))
452 call get_command_argument(iarg, arg)
453 xuv_plus_ir_outdir % str = trim(arg)
455 call get_command_argument(iarg, arg)
456 xuv_minus_ir_outdir % str = trim(arg)
458 case (
'--properties')
460 call get_command_argument(iarg, arg)
461 properties % str = trim(arg)
464 print
'(2a)',
'Unknown command line argument ', trim(arg)
473 if (basis == -1)
then
474 print
'(a)',
'Missing one of --cartesian/--spherical'
482 open (newunit = u, file = trim(filenames(ifile)), action =
'read', iostat = stat)
484 print
'(a)',
'Failed to open file "', trim(filenames(ifile)),
'"'
487 if (ifile == 0)
allocate (xuv_plus_ir_filenames(0))
488 if (ifile == 1)
allocate (xuv_minus_ir_filenames(0))
491 read (u,
'(a)', iostat = stat) arg
492 if (is_iostat_end(stat))
exit
494 print
'(a,i0,3a)',
'Error ', stat,
' while reading from file "', filenames(ifile),
'"'
497 allocate (string_array(n + 1))
498 if (ifile == 1 .and. n >= 1) string_array(1:n) = xuv_plus_ir_filenames
499 if (ifile == 2 .and. n >= 1) string_array(1:n) = xuv_minus_ir_filenames
501 string_array(n) % str = trim(arg)
502 if (ifile == 1)
call move_alloc(string_array, xuv_plus_ir_filenames)
503 if (ifile == 2)
call move_alloc(string_array, xuv_minus_ir_filenames)
508 print
'(a,*(1x,i0,a))',
'Photon orders:', ord1,
' (extend to', ord1+abs(ext1),
'),', ord2,
' (extend to', ord2+abs(ext2),
')'
509 print
'(a,1x,a)',
'Angular basis:', merge(
'spherical',
'cartesian', sph)
510 print
'(a,1x,2(1x,f0.3))',
'XUV polarization:', polar
511 print
'(a,1x,2(1x,f0.3))',
'IR polarization:', polarir
512 print
'(a,5x,i0)',
'Max lab L:', maxlab
513 if (
allocated(theta)) print
'(a,1x,*(1x,f0.1))',
'Polar angles:', theta
514 if (
allocated(phi)) print
'(a,1x,*(1x,f0.1))',
'Azimut angles:', phi
526 subroutine read_raw_multipoles (order1, order2, sph, ntarg, maxl, nesc, target_states, chains1, chains2, &
527 XUV_plus_IR_filenames, XUV_minus_IR_filenames, M_XUV_plus_IR, M_XUV_minus_IR)
529 type(
string),
allocatable,
intent(in) :: XUV_plus_IR_filenames(:), XUV_minus_IR_filenames(:)
531 complex(real64),
allocatable,
intent(inout) :: M_XUV_plus_IR(:, :, :, :), M_XUV_minus_IR(:, :, :, :)
532 integer,
allocatable,
intent(inout) :: target_states(:), chains1(:, :), chains2(:, :)
534 logical,
intent(in) :: sph
535 integer,
intent(in) :: order1, order2
536 integer,
intent(out) :: ntarg, maxl, nesc
538 character(len=:),
allocatable :: filename
539 complex(real64),
allocatable :: buffer(:)
540 integer,
allocatable :: new_target_states(:)
541 integer :: i, idx, ichain, nchain1, nchain2, l, m, nene, ifile, nplus, nminus
547 allocate (target_states(ntarg))
549 nplus =
size(xuv_plus_ir_filenames)
550 nminus =
size(xuv_minus_ir_filenames)
555 if (nplus /= nminus)
then
556 print
'(a,i0,a,i0,a,/)',
'Warning: Number of XUV-IR and XUV+IR files is different (', nminus,
' vs ', nplus,
').'
560 do ifile = 1, nplus + nminus
561 if (ifile <= nplus) filename = xuv_plus_ir_filenames(ifile) % str
562 if (ifile > nplus) filename = xuv_minus_ir_filenames(ifile - nplus) % str
563 print
'(3A)',
'Reading file "', filename,
'"...'
565 if (ifile <= nplus)
call parse_file_name(filename, order1, sph, ichain, i, l, m)
566 if (ifile > nplus)
call parse_file_name(filename, order2, sph, ichain, i, l, m)
567 print
'(2(A,I0),A,SP,I0)',
' - target state: ', i,
', partial wave: ', l,
', ', m
568 print
'(A,I0)',
' - number of energies: ', nene
569 if (ifile <= nplus) print
'(A,*(1x,I0))',
' - absorption chain:', chains1(:, ichain)
570 if (ifile > nplus) print
'(A,*(1x,I0))',
' - absorption chain:', chains2(:, ichain)
572 nesc = max(nesc, nene)
573 if (findloc(target_states, i, 1) == 0)
then
574 allocate (new_target_states(ntarg + 1))
575 new_target_states(1 : ntarg) = target_states(1:ntarg)
576 new_target_states(1 + ntarg) = i
577 call move_alloc(new_target_states, target_states)
580 deallocate (filename)
584 allocate (m_xuv_plus_ir(nesc, (maxl + 1)**2, nchain1, ntarg), m_xuv_minus_ir(nesc, (maxl + 1)**2, nchain2, ntarg))
590 do ifile = 1, nplus + nminus
591 if (ifile <= nplus)
then
592 filename = xuv_plus_ir_filenames(ifile) % str
595 filename = xuv_minus_ir_filenames(ifile - nplus) % str
599 idx = findloc(target_states, i, 1)
600 if (ifile <= nplus) m_xuv_plus_ir(1:nene, l*l + l + m + 1, ichain, idx) = buffer(1:nene)
601 if (ifile > nplus) m_xuv_minus_ir(1:nene, l*l + l + m + 1, ichain, idx) = buffer(1:nene)
602 deallocate (filename)
676 character(len=*),
intent(in) :: filename
677 logical,
intent(in) :: sph
678 integer,
intent(in) :: order
679 integer,
intent(out) :: ichain, i, l, m
681 character(len=1) :: c(order)
682 integer :: j, k, q(order), u, v
684 k = scan(filename,
'(', back = .true.)
686 v = scan(filename(1:k-1),
'-', back = .true.)
687 u = scan(filename(1:v-1),
'-', back = .true.)
689 if (v - u /= order + 1)
then
690 print
'(3A,I0)',
'Name of the file "', filename,
'" is not consistent with the given order ', order
695 c(j) = filename(k - 2 - order + j : k - 2 - order + j)
701 case (
'm'); q(j) = -1
703 case (
'p'); q(j) = +1
705 print
'(3A)',
'Dipole component "', c(j),
'" is not valid in spherical basis.'
710 case (
'y'); q(j) = -1
712 case (
'x'); q(j) = +1
714 print
'(3A)',
'Dipole component "', c(j),
'" is not valid in Cartesian basis.'
722 ichain = 3*(ichain - 1) + q(j) + 2
726 k = j + scan(filename(j:),
',') - 1
727 read (filename(j : k - 1), *) i
730 k = j + scan(filename(j:),
',') - 1
731 read (filename(j : k - 1), *) l
734 k = j + scan(filename(j:),
')') - 1
735 read (filename(j : k - 1), *) m
809 subroutine extend_order (ord, MM, chains, ext, Ek, wIR, target_states, echl, prop, maxl, outdir)
811 use coupling_obj_gbl,
only: couplings_type
815 complex(real64),
allocatable,
intent(inout) :: MM(:, :, :, :)
816 integer,
intent(in) :: ord, ext, target_states(:)
817 integer,
intent(in) :: maxl
818 real(real64),
intent(in) :: wIR
819 real(real64),
allocatable,
intent(in) :: Ek(:), echl(:), prop(:, :, :)
820 type(
string),
intent(in) :: outdir
821 integer,
allocatable,
intent(inout) :: chains(:, :)
823 complex(real64),
allocatable :: M0(:, :, :, :), Apws(:, :), Aion(:, :)
824 integer,
allocatable :: chains0(:, :)
826 type(couplings_type) :: cpl
827 character(len=1) :: cmptname(3) = [
'y',
'z',
'x']
828 character(len=1024) :: filename, strchain
830 integer :: order, nesc, nchain, nchain0, ntarg, l, m, n, u, lambda, mu, ipw, jpw, itarg, jtarg, &
831 ichain, jchain, ie, iex, compt
832 real(real64) :: gaunt, dEIR, Qion, Qpws, kappa, k
837 deir = merge(wir, -wir, ext > 0)
839 call cpl % prec_cgaunt(maxl)
841 allocate (apws(nesc, 0:maxl), aion(nesc, ntarg))
848 nchain0 =
size(chains, 2)
851 print
'(/,a,i0,/)',
'Extending pathway to order ', order
853 call move_alloc(mm, m0)
854 call move_alloc(chains, chains0)
857 allocate (mm(nesc, (maxl + 1)**2, nchain, ntarg))
863 print
'(2x,2(a,i0))',
'Precomputing Akkl factors for target ', itarg,
', and l = ', l
867 if (ek(ie) - echl(itarg) + deir*iex <= 0) cycle
868 k = sqrt(2*(ek(ie) - echl(itarg) + deir*iex))
869 do lambda = abs(l - 1), min(maxl, l + 1)
870 if (ek(ie) - echl(itarg) + deir*(iex - 1) <= 0) cycle
871 kappa = sqrt(2*(ek(ie) - echl(itarg) + deir*(iex - 1)))
872 apws(ie, lambda) = akkl(kappa, lambda, k, l, 1)
875 if (ek(ie) - echl(jtarg) + deir*(iex - 1) <= 0) cycle
876 kappa = sqrt(2*(ek(ie) - echl(jtarg) + deir*(iex - 1)))
877 aion(ie, jtarg) = akkl(kappa, l, k, l, 0)
881 ipw = l*l + l + m + 1
883 do lambda = abs(l - 1), min(maxl, l + 1)
884 do mu = -lambda, lambda
885 jpw = lambda*lambda + lambda + mu + 1
887 gaunt = cpl % rgaunt(l, lambda, 1, m, mu, compt)
889 qpws = sqrt(4*
pi/3) * gaunt
890 do jchain = 1, nchain0
891 ichain = 3*(jchain - 1) + compt + 2
892 mm(:, ipw, ichain, itarg) = mm(:, ipw, ichain, itarg) &
893 + qpws * apws(:, lambda) * m0(:, jpw, jchain, itarg)
902 qion = prop(target_states(itarg), target_states(jtarg), compt + 2)
904 do jchain = 1, nchain0
905 ichain = 3*(jchain - 1) + compt + 2
906 mm(:, ipw, ichain, itarg) = mm(:, ipw, ichain, itarg) &
907 + qion * aion(:, jtarg) * m0(:, ipw, jchain, jtarg)
918 if (len_trim(outdir % str) /= 0)
then
919 print
'(/,3a)',
'Writing extended partial-wave amplitudes to "', outdir % str,
'"'
921 do ichain = 1,
size(mm, 3)
924 ipw = l*l + l + m + 1
925 if (all(mm(:, ipw, ichain, itarg) == 0)) cycle
926 write (strchain,
'(*(a))') [(cmptname(mod(ichain - 1, 3**n)/3**(n - 1) + 1), n = 1, order)]
927 write (filename,
'(3a,2(i0,a),sp,i0,a)')
'rawdip-', trim(strchain),
'-(', itarg,
',', l,
',', m,
').txt'
928 open (newunit = u, file = outdir % str //
'/' // filename, action =
'write', form =
'formatted')
929 write (u,
'(2e25.15)') mm(:, ipw, ichain, itarg)
935 open (newunit = u, file = outdir % str //
'/' //
'pe_energies.txt', action =
'write', form =
'formatted')
936 write (u,
'(e25.15)') [(ek(ie) + ext*wir, ie = 1, nesc)]
1005 subroutine calculate_oriented_dipoles (maxl, chains1, chains2, ntarg, nesc, Mp, Mm, axis, axisIR, theta, phi)
1007 use dipelm_defs,
only: pi
1008 use dipelm_special_functions,
only: a_re_sp_harm, a_sp_harm
1011 integer,
intent(in) :: maxl, ntarg, nesc
1012 integer,
allocatable,
intent(in) :: chains1(:, :), chains2(:, :)
1013 real(real64),
intent(in) :: axis(3), axisIR(3)
1014 real(real64),
allocatable,
intent(in) :: theta(:), phi(:)
1015 complex(real64),
allocatable,
intent(in) :: Mp(:, :, :, :), Mm(:, :, :, :)
1017 real(real64),
allocatable :: Xlm(:, :), Yl0(:, :), sins(:), coss(:)
1018 complex(real64),
allocatable :: Qmol(:, :), Qint(:, :), Qaxs(:, :), Qrec(:, :), QM(:), Xvalues(:)
1020 integer :: l1, l2, m1, m2, pw1, pw2, pw1a, pw2a, c1, c2, i1, i2, icomp, iang, nang, ntheta, nphi, itg, ncompt(3)
1021 real(real64) :: cav, cai, cax, rtheta, rphi, zero = 0
1026 if (
allocated(theta)) ntheta =
size(theta)
1027 if (
allocated(phi)) nphi =
size(phi)
1029 nang = max(ntheta, nphi)
1031 if (nang == 0)
return
1033 allocate (xlm((maxl + 1)**2, nang), yl0((maxl + 1)**2, nang), qmol(nesc, nang), qaxs(nesc, nang), qrec(nesc, nang), &
1034 qint(nesc, 1), sins(nang), coss(nang), qm(nesc))
1046 if (ntheta > 0) rtheta = theta(1 + mod(iang - 1, ntheta)) * pi / 180
1047 if (nphi > 0) rphi = phi(1 + mod(iang - 1, nphi)) * pi / 180
1049 call a_re_sp_harm(maxl, rtheta, rphi, xvalues)
1050 xlm(:, iang) = real(xvalues, real64)
1051 deallocate (xvalues)
1053 call a_sp_harm(maxl, rtheta, zero, xvalues)
1054 yl0(:, iang) = real(xvalues, real64)
1055 deallocate (xvalues)
1057 sins(iang) = sin(rtheta)
1058 coss(iang) = cos(rtheta)
1065 pw1 = l1*l1 + l1 + m1 + 1
1066 pw1a = l1*l1 + l1 + abs(m1) + 1
1069 pw2 = l2*l2 + l2 + m2 + 1
1070 pw2a = l2*l2 + l2 + abs(m2) + 1
1071 do c1 = 1,
size(chains1, 2)
1072 do c2 = 1,
size(chains2, 2)
1077 if (sum(axis**2) > 0 .and. sum(axisir**2) > 0)
then
1080 do icomp = 1,
size(chains1, 1)
1081 i1 = 1 + mod(chains1(icomp, c1) + 2, 3)
1082 ncompt(i1) = ncompt(i1) + 1
1083 cax = cax * merge(axis(i1), axisir(i1), icomp == 1)
1085 do icomp = 1,
size(chains2, 1)
1086 i2 = 1 + mod(chains2(icomp, c2) + 2, 3)
1087 ncompt(i2) = ncompt(i2) + 1
1088 cax = cax * merge(axis(i2), axisir(i2), icomp == 1)
1092 if (ncompt(1) == 0 .and. ncompt(2) == 0) cai = 2*pi
1093 if (ncompt(1) == 2 .neqv. ncompt(2) == 2) cai = pi
1094 if (ncompt(1) == 2 .and. ncompt(2) == 2) cai = pi/4
1095 if (ncompt(1) == 4 .or. ncompt(2) == 4) cai = 3*pi/4
1096 if (any(mod(ncompt, 2) /= 0)) cai = 0
1097 cai = cai * axis(3)**ncompt(3) * hypot(axis(1), axis(2))**(ncompt(1) + ncompt(2))
1104 if (cax /= 0 .or. cai /= 0 .or. cav /= 0)
then
1105 qm = conjg(mp(:, pw1, c1, itg)) * mm(:, pw2, c2, itg)
1106 if (all(qm == 0)) cycle
1110 qmol(:, iang) = qmol(:, iang) + qm * cax * xlm(pw1, iang) * xlm(pw2, iang)
1112 if (cax /= 0 .and. l1 == l2 .and. m1 == m2 .and. iang == 1)
then
1113 qint(:, 1) = qint(:, 1) + qm * cax
1115 if (m1 == m2 .and. cai /= 0)
then
1116 qaxs(:, iang) = qaxs(:, iang) + qm * cai * yl0(pw1a, iang) * yl0(pw2a, iang)
1118 if (m1 == m2 .and. cav /= 0)
then
1119 qrec(:, iang) = qrec(:, iang) + qm * cav * yl0(pw1a, iang) * yl0(pw2a, iang)
logical function process_command_line(ord1, ord2, ext1, ext2, sph, maxlab, polar, polarir, theta, phi, ek1, ek2, wir, properties, xuv_plus_ir_filenames, xuv_minus_ir_filenames, xuv_plus_ir_outdir, xuv_minus_ir_outdir)
Read options from the command line.