Multidip 1.0
Multi-photon matrix elements
Loading...
Searching...
No Matches
multidip_rabitt_delays.F90
Go to the documentation of this file.
1! Copyright 2021
2!
3! For a comprehensive list of the developers that contributed to these codes
4! see the UK-AMOR website.
5!
6! This file is part of UKRmol-out (UKRmol+ suite).
7!
8! UKRmol-out is free software: you can redistribute it and/or modify
9! it under the terms of the GNU General Public License as published by
10! the Free Software Foundation, either version 3 of the License, or
11! (at your option) any later version.
12!
13! UKRmol-out is distributed in the hope that it will be useful,
14! but WITHOUT ANY WARRANTY; without even the implied warranty of
15! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16! GNU General Public License for more details.
17!
18! You should have received a copy of the GNU General Public License
19! along with UKRmol-out (in source/COPYING). Alternatively, you can also visit
20! <https://www.gnu.org/licenses/>.
21!
22
23!> \brief Calculate RABITT delays from raw multipole elements
24!> \author J Benda
25!> \date 2021 - 2024
26!>
27!> Having (spherical or Cartesian) raw multipole elements calculated by MULTIDIP for the two different absorption/emission pathways,
28!> evaluate the corresponding discrete time delays, unresolved (i.e. averaged) in emission direction as well as in molecular
29!> orientation. The raw multipole elements filenames are provided on the command line and they are expected to bear either the
30!> original file name assigned by MULTIDIP or additional stem suffixes, for instance "-smooth" as added by the utility program
31!> *multidip_smooth_rawdips*. Example usage:
32!> ```
33!> multidip_rabitt_delays --cartesian \
34!> --two-photon \
35!> --xuv-plus-ir <(ls multidip.2.avg.XUV+IR.r100/rawdip-[xyz]*-*) \
36!> --xuv-minus-ir <(ls multidip.2.avg.XUV-IR.r100/rawdip-[xyz]*-*)
37!> ```
38!> See the program help for details. Note that the program can be used to calculate one-photon delays, too. For this to work,
39!> one needs to produce two sets of the one-photon raw transition dipoles that are offset in energies by 2*omega_IR. These
40!> two sets are then used with `--xuv-plus-ir` and `--xuv-minus-ir` (with smaller and larger energies, respectively). The results
41!> are then for energies in between.
42!>
43!> When the parameters `--polar`, `--theta` and `--phi` are specified, molecular frame delays will be calculated as well. The
44!> parameter `--polar` specifies the direction of the polarization axis the polar and azimuthal angle in degrees. The parameters
45!> `--theta` and `--phi` specify the emission directions in the molecular frame; arbitrary number of angles in degrees can be given.
46!> If one of these is omitted, it is assumed to be zero. If the two arrays of angles have unequal lengths, the shorter one is
47!> cycled over as long as necessary. When `--theta` and/or `--phi` are given, the program will produce filws with the RABITT
48!> interference term called "rabitt-signal-mol-?.txt", where "?" is the index of the emission direction. Then there weill be
49!> two more sets
50!> of results:
51!> - "rabitt-signal-axs-?.txt" - integrated over orientations of the polarization, preserving the polar angle of the polarization
52!> vector
53!> - "rabitt-signal-rec-?.txt" - integrated over orientations of the polarizatoin (both angles)
54!> These two semi-averaged results also include integration over azimuthal emission angle. Molecular frame output is only
55!> computed with Cartesian angular basis.
56!>
58
59 use iso_fortran_env, only: real64
60#ifdef HAVE_NO_FINDLOC
61 use algorithms, only: findloc
62#endif
63
64 implicit none
65
66 type string
67 character(:), allocatable :: str
68 end type string
69
70 call rabitt_main
71
72contains
73
74 !> \brief Print program usage information
75 !> \author J Benda
76 !> \date 2021 - 2024
77 !>
78 subroutine print_help
79
80 print '(A)', 'Calculate discrete RABITT time delays using the two- (or multi-)photon raw dipole elements'
81 print '( )'
82 print '(A)', 'Usage:'
83 print '( )'
84 print '(A)', ' multidip_rabitt_delays [OPTIONS] --xuv+ir <FILE1> --xuv-ir <FILE2>'
85 print '( )'
86 print '(A)', 'General options:'
87 print '( )'
88 print '(A)', ' --help Display this help'
89 print '(A)', ' --one-photon Calculate one-photon delays (equivalent to --orders 1 1)'
90 print '(A)', ' --two-photon Calculate two-photon delays (equivalent to --orders 2 2)'
91 print '(A)', ' --orders M N Calculate mixed-photon delays'
92 print '(A)', ' --extend P Q Extend the orders to M+|P| and N+|Q| using per-pw asymptotic approximation'
93 print '(A)', ' --spherical Assume matrix elements in the spherical basis'
94 print '(A)', ' --cartesian Assume matrix elements in the Cartesian basis'
95 print '(A)', ' --rawdips FILE1 FILE2 File with paths to files containing raw matrix elements for the XUV+/-IR pathways'
96 print '( )'
97 print '(A)', 'Higher-order extension control options:'
98 print '( )'
99 print '(A)', ' --ir-energy EIR Energy of IR photon (in au, needed for --extend)'
100 print '(A)', ' --properties FILE Path to the residual ion properties file (needed'
101 print '(A)', ' --energies FILE1 FILE2 Files with photoelectron energies (in au) in the 1st channel (for --extend)'
102 print '(A)', ' --out-dir DIR1 DIR2 Directory for output of XUV+/-IR matrix elements calculated via --extend'
103 print '( )'
104 print '(A)', 'Angular distribution control options:'
105 print '( )'
106 print '(A)', ' --max-lab MAXL Maximal angular momentum for asymmetry parameer (default: 0)'
107 print '(A)', ' --polar THETA PHI Polarization direction of XUV in molecular frame (degrees, default: 0 0, i.e. z)'
108 print '(A)', ' --polar-ir THETA PHI As above but for IR, by default oriented in the same direction as XUV'
109 print '(A)', ' --theta ANGLE(s) Polar emission angles (degrees, default: 0)'
110 print '(A)', ' --phi ANGLE(s) Azimuthal emission angles (degrees, default: 0)'
111 print '( )'
112 print '(A)', 'The files containing the list of paths to raw dipole data are assumed to contain one path on each line.&
113 & A convenient way how to pass all files of a given mask to this program in some Unix-like shells is using&
114 & the so-called process substitution like this:'
115 print '( )'
116 print '(A)', ' multidip_rabitt_delays --rawdips <(ls XUV+IR/rawdip-[xyz]-*) <(ls XUV-IR/rawdip-[xyz]-*)'
117 print '( )'
118 print '(A)', 'Note that the file names provided on the command line need to satisfy the original MULTIDIP naming scheme,&
119 & so that it is possible to extract the partial wave quantum numbers.'
120 print '( )'
121 print '(A)', 'The resulting RABITT cross section interference term will be written to file "rabitt-signal-L0-xyz.txt" or&
122 & "rabitt-signal-L0-sph.txt" depending on the selected mode. To obtain the resulting&
123 & molecular orientation averaged photoionization delays, one needs to take the complex argument and divide&
124 & it by 2*omega_IR.'
125
126 end subroutine print_help
127
128
129 !> \brief Main program
130 !> \author J Benda
131 !> \date 2021 - 2024
132 !>
133 !> Read the intermediate data from disk and produces the (orientation averaged) delays.
134 !>
135 subroutine rabitt_main
136
137 use iso_fortran_env, only: output_unit
138 use mpi_gbl, only: mpi_mod_start, mpi_mod_finalize
142
143 type(string), allocatable :: XUV_plus_IR_filenames(:), XUV_minus_IR_filenames(:)
144 type(string) :: XUV_plus_IR_outdir, XUV_minus_IR_outdir, properties
145
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(:, :, :, :)
149
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
153
154 integer, allocatable :: target_states(:), chains1(:, :), chains2(:, :)
155
156 integer :: i, L, order1, order2, extend1, extend2, maxl, ntarg, nesc, maxlab, lutarg, p(nMaxPhotons)
157 logical :: sph
158 character(len=200) :: str
159
160 if (command_argument_count() == 0) then
161 call print_help
162 return
163 end if
164
165 call print_ukrmol_header(output_unit)
166 call mpi_mod_start
167
168 print '(/,A,/)', 'Program RABITT: Calculation of two-photon interference amplitudes'
169
170 ! set lab-frame polarisations to zero
171 p = 0
172
173 if (.not. process_command_line(order1, order2, extend1, extend2, sph, maxlab, polar, polarir, &
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
177 return
178 end if
179
180 ! read raw multipole elements from disk
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
185
186 ! convert Cartesian matrix elements to spherical basis
187 if (sph) then
188 if (extend1 /= 0 .or. extend2 /= 0) then
189 print '(/,a)', 'Error: Asymptotic extension not implemented for --spherical'
190 stop 1
191 end if
192 m_xuv_plus_ir_sph = m_xuv_plus_ir_xyz
193 m_xuv_minus_ir_sph = m_xuv_minus_ir_xyz
194 else
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'
198 stop 1
199 end if
200 if (wir <= 0) then
201 print '(/,a)', 'Error: Need a positive IR energy (--ir-energy) on the command line for extending'
202 stop 1
203 end if
204 if (len_trim(properties % str) == 0) then
205 print '(/,a)', 'Error: Need the residual ion properties file (--properties) for extending'
206 stop 1
207 end if
208 open (newunit = lutarg, file = properties % str, action = 'read', form = 'formatted')
209 call read_target_properties(lutarg, prop, echl)
210 close (lutarg)
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)
216 end if
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)
219 call convert_xyz_to_sph(m_xuv_plus_ir_xyz, m_xuv_plus_ir_sph, maxl, chains1)
220 call convert_xyz_to_sph(m_xuv_minus_ir_xyz, m_xuv_minus_ir_sph, maxl, chains2)
221 end if
222
223 ! allocate final storage for the quadratic dipoles
224 allocate (mm(2 + ntarg, nesc), mm0(2 + ntarg, nesc))
225
226 do l = 0, min(maxlab, order1 + abs(extend1) + order2 + abs(extend2))
227
228 str = 'rabitt-signal-L'
229
230 ! for checking purposes, evaluate the isotropic parameter in the Cartesian basis
231 if (l == 0 .and. .not. sph) then
232 call calculate_quadratic_dipole_xyz(mm, l, maxl, chains1, chains2, ntarg, nesc, &
233 m_xuv_plus_ir_xyz, m_xuv_minus_ir_xyz)
234 call write_quadratic_dipoles(l, mm, str, '-xyz')
235 end if
236
237 ! evaluate the asymmetry parameter in the spherical basis
238 call calculate_quadratic_dipole_sph(mm, l, maxl, chains1, chains2, ntarg, nesc, &
239 m_xuv_plus_ir_sph, m_xuv_minus_ir_sph, p)
240 call write_quadratic_dipoles(l, mm, str, '-sph')
241
242 if (l == 0) then
243 mm0 = mm
244 else
245 do i = 3, 2 + ntarg
246 where (mm0(i, :) /= 0)
247 mm(i,:) = mm(i,:) / mm0(i,:)
248 elsewhere
249 mm(i,:) = 0
250 end where
251 end do
252
253 str = 'rabitt-beta-L'
254 call write_quadratic_dipoles(l, mm, str, '')
255 end if
256
257 end do
258
259 if (.not. sph) then
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)) ]
264 call calculate_oriented_dipoles(maxl, chains1, chains2, ntarg, nesc, &
265 m_xuv_plus_ir_xyz, m_xuv_minus_ir_xyz, axis, axisir, theta, phi)
266 end if
267
268 print '(/,A)', 'Done.'
269
270 call mpi_mod_finalize
271
272 end subroutine rabitt_main
273
274
275 !> \brief Read options from the command line
276 !> \author J Benda
277 !> \date 2022 - 2024
278 !>
279 !> Obtain command line options, in particular the list of transition multipole files written by MULTIDIP.
280 !>
281 !> \param[out] ord1 Photon absorption order for conjugated pathway
282 !> \param[out] ord2 Photon absorption order for non-conjugated pathway
283 !> \param[out] ext1 Requested asymptotic extension of the absorption order in conjugated pathway
284 !> \param[out] ext2 Requested asymptotic extension of the absorption order in non-conjugated pathway
285 !> \param[out] sph Whether the spherical basis is used
286 !> \param[out] maxlab Highest angular momentum to consider in the laboratory frame
287 !> \param[out] polar Polarization vector of the XUV field in the molecular frame
288 !> \param[out] polarIR Polarization vector of the IR field in the molecular frame
289 !> \param[inout] theta List of polar emission angles
290 !> \param[inout] phi List of azimuthal emission angles
291 !> \param[inout] Ek1 List of photoelectron kinetic energies on input (needed for extension to higher orders)
292 !> \param[inout] Ek2 List of photoelectron kinetic energies on input (needed for extension to higher orders)
293 !> \param[inout] properties Target properties file path
294 !> \param[out] wIR Energy of the IR quantum (needed for extension to higher orders)
295 !> \param[inout] XUV_plus_IR_filenames List of files with transition multipoles for XUV+IR pathway
296 !> \param[inout] XUV_minus_IR_filenames List of files with transition multipoles for XUV-IR pathway
297 !> \param[inout] XUV_plus_IR_outdir Output directory for extended XUV+IR amplitudes
298 !> \param[inout] XUV_minus_IR_outdir Output directory for extended XUV-IR amplitudes
299 !>
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, &
302 XUV_minus_IR_outdir)
303
304 integer, intent(out) :: ord1, ord2, ext1, ext2, maxlab
305 real(real64), intent(out) :: polar(2), polarir(2), wir
306 logical, intent(out) :: sph
307
308 real(real64), allocatable, intent(inout) :: theta(:), phi(:), ek1(:), ek2(:)
309 real(real64), allocatable :: real_array(:)
310
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(:)
314
315 character(len=8192) :: arg, filenames(2)
316
317 integer :: iarg, narg, basis, n, ifile, stat, u
318
319 narg = command_argument_count()
320 iarg = 1
321 polar = 0
322 polarir = 0
323 ord1 = 2
324 ord2 = 2
325 ext1 = 0
326 ext2 = 0
327 basis = -1
328 maxlab = 0
329 wir = 0
330 process_command_line = .true.
331
332 main_loop: do while (iarg <= narg)
333
334 call get_command_argument(iarg, arg)
335
336 select case (trim(arg))
337
338 case ('--help')
339 call print_help
340 process_command_line = .false.
341 return
342
343 case ('--one-photon')
344 ord1 = 1
345 ord2 = 1
346
347 case ('--two-photon')
348 ord1 = 2
349 ord2 = 2
350
351 case ('--orders')
352 iarg = iarg + 1
353 call get_command_argument(iarg, arg)
354 read (arg, *) ord1
355 iarg = iarg + 1
356 call get_command_argument(iarg, arg)
357 read (arg, *) ord2
358
359 case ('--extend')
360 iarg = iarg + 1
361 call get_command_argument(iarg, arg)
362 read (arg, *) ext1
363 iarg = iarg + 1
364 call get_command_argument(iarg, arg)
365 read (arg, *) ext2
366
367 case ('--cartesian')
368 basis = 1
369
370 case ('--spherical')
371 basis = 2
372
373 case ('--max-lab')
374 iarg = iarg + 1
375 call get_command_argument(iarg, arg)
376 read (arg, *) maxlab
377
378 case ('--polar')
379 iarg = iarg + 1
380 call get_command_argument(iarg, arg)
381 read (arg, *) polar(1)
382 iarg = iarg + 1
383 call get_command_argument(iarg, arg)
384 read (arg, *) polar(2)
385 polarir = polar
386
387 case ('--polar-ir')
388 iarg = iarg + 1
389 call get_command_argument(iarg, arg)
390 read (arg, *) polarir(1)
391 iarg = iarg + 1
392 call get_command_argument(iarg, arg)
393 read (arg, *) polarir(2)
394
395 case ('--theta')
396 iarg = iarg + 1
397 do while (iarg <= narg)
398 call get_command_argument(iarg, arg)
399 if (arg(1:2) == '--') cycle main_loop
400 n = 0
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)
406 iarg = iarg + 1
407 end do
408
409 case ('--phi')
410 iarg = iarg + 1
411 do while (iarg <= narg)
412 call get_command_argument(iarg, arg)
413 if (arg(1:2) == '--') cycle main_loop
414 n = 0
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)
420 iarg = iarg + 1
421 end do
422
423 case ('--energies')
424 iarg = iarg + 1
425 call get_command_argument(iarg, arg)
426 call read_real_array(arg, ek1)
427 iarg = iarg + 1
428 call get_command_argument(iarg, arg)
429 call read_real_array(arg, ek2)
430
431 case ('--ir-energy')
432 iarg = iarg + 1
433 call get_command_argument(iarg, arg)
434 read (arg, *) wir
435
436 case ('--xuv-plus-ir', '--xuv+ir')
437 iarg = iarg + 1
438 call get_command_argument(iarg, filenames(1))
439
440 case ('--xuv-minus-ir', '--xuv-ir')
441 iarg = iarg + 1
442 call get_command_argument(iarg, filenames(2))
443
444 case ('--rawdips')
445 iarg = iarg + 1
446 call get_command_argument(iarg, filenames(1))
447 iarg = iarg + 1
448 call get_command_argument(iarg, filenames(2))
449
450 case ('--out-dir')
451 iarg = iarg + 1
452 call get_command_argument(iarg, arg)
453 xuv_plus_ir_outdir % str = trim(arg)
454 iarg = iarg + 1
455 call get_command_argument(iarg, arg)
456 xuv_minus_ir_outdir % str = trim(arg)
457
458 case ('--properties')
459 iarg = iarg + 1
460 call get_command_argument(iarg, arg)
461 properties % str = trim(arg)
462
463 case default
464 print '(2a)', 'Unknown command line argument ', trim(arg)
465 stop 1
466
467 end select
468
469 iarg = iarg + 1
470
471 end do main_loop
472
473 if (basis == -1) then
474 print '(a)', 'Missing one of --cartesian/--spherical'
475 stop 1
476 end if
477
478 sph = basis == 2
479
480 ! read filenames from the XUV+IR and XUV-IR files
481 do ifile = 1, 2
482 open (newunit = u, file = trim(filenames(ifile)), action = 'read', iostat = stat)
483 if (stat /= 0) then
484 print '(a)', 'Failed to open file "', trim(filenames(ifile)), '"'
485 stop 1
486 end if
487 if (ifile == 0) allocate (xuv_plus_ir_filenames(0))
488 if (ifile == 1) allocate (xuv_minus_ir_filenames(0))
489 n = 0
490 do
491 read (u, '(a)', iostat = stat) arg
492 if (is_iostat_end(stat)) exit
493 if (stat /= 0) then
494 print '(a,i0,3a)', 'Error ', stat, ' while reading from file "', filenames(ifile), '"'
495 stop 1
496 end if
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
500 n = n + 1
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)
504 end do
505 close (u)
506 end do
507
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
515 print '()'
516
517 end function process_command_line
518
519
520 !> \brief Read multipoles from disk
521 !> \author J Benda
522 !> \date 2021 - 2022
523 !>
524 !> Read all raw multipole files specified on the command line and store the data in `M_XUV_plus_IR` and `M_XUV_minus_IR`.
525 !>
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)
528
529 type(string), allocatable, intent(in) :: XUV_plus_IR_filenames(:), XUV_minus_IR_filenames(:)
530
531 complex(real64), allocatable, intent(inout) :: M_XUV_plus_IR(:, :, :, :), M_XUV_minus_IR(:, :, :, :)
532 integer, allocatable, intent(inout) :: target_states(:), chains1(:, :), chains2(:, :)
533
534 logical, intent(in) :: sph
535 integer, intent(in) :: order1, order2
536 integer, intent(out) :: ntarg, maxl, nesc
537
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
542
543 ntarg = 0
544 maxl = 0
545 nesc = 0
546
547 allocate (target_states(ntarg))
548
549 nplus = size(xuv_plus_ir_filenames)
550 nminus = size(xuv_minus_ir_filenames)
551
552 call setup_chains(order1, nchain1, chains1)
553 call setup_chains(order2, nchain2, chains2)
554
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, ').'
557 end if
558
559 ! first pass over all files to get limiting values
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, '"...'
564 call read_file_data(filename, nene)
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)
571 maxl = max(maxl, l)
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)
578 ntarg = ntarg + 1
579 end if
580 deallocate (filename)
581 end do
582
583 ! resize the multipole storage
584 allocate (m_xuv_plus_ir(nesc, (maxl + 1)**2, nchain1, ntarg), m_xuv_minus_ir(nesc, (maxl + 1)**2, nchain2, ntarg))
585
586 m_xuv_plus_ir = 0
587 m_xuv_minus_ir = 0
588
589 ! actually read the dipoles now
590 do ifile = 1, nplus + nminus
591 if (ifile <= nplus) then
592 filename = xuv_plus_ir_filenames(ifile) % str
593 call parse_file_name(filename, order1, sph, ichain, i, l, m)
594 else
595 filename = xuv_minus_ir_filenames(ifile - nplus) % str
596 call parse_file_name(filename, order2, sph, ichain, i, l, m)
597 end if
598 call read_file_data(filename, nene, buffer)
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)
603 end do
604
605 end subroutine read_raw_multipoles
606
607
608 !> \brief Assemble absorption chains
609 !> \author J Benda
610 !> \date 2021 - 2023
611 !>
612 !> Construct database of all possible dipole component absorption chains. This is a two-dimensional
613 !> array, where the second index numbers the individual pathway, while the first index numbers the
614 !> absorbed photons. Polarizations of the photons are denoted by labels -1, 0, +1. The pathways are
615 !> organized in lexicographical order. For example, the two-photon pathways look like this:
616 !>
617 !> \verbatim
618 !> 1: -1, -1
619 !> 2: -1, 0
620 !> 3: -1, +1
621 !> 4: 0, -1
622 !> 5: 0, 0
623 !> 6: 0, +1
624 !> 7: +1, -1
625 !> 8: +1, 0
626 !> 9: +1, +1
627 !> \endverbatim
628 !>
629 subroutine setup_chains (order, nchain, chains)
630
631 integer, intent(in) :: order
632 integer, intent(out) :: nchain
633 integer, allocatable, intent(inout) :: chains(:, :)
634
635 integer :: i, idx
636
637 nchain = 3**order
638
639 allocate (chains(order, nchain))
640
641 ! the first pathway uses the lowest labels for all photons
642 chains(:, 1) = -1
643
644 ! build other pathways one after another
645 do idx = 2, 3**order
646
647 ! use the previous pathway as starting point
648 chains(:, idx) = chains(:, idx - 1)
649
650 ! atempt to increment the sequence (least significant digit last)
651 increment_chain: do i = order, 1, -1
652 if (chains(i, idx) < 1) then
653 ! if possible, increment the right-most value and exit
654 chains(i, idx) = chains(i, idx) + 1
655 exit increment_chain
656 else
657 ! otherwise wrap around to the lowest index and try next
658 chains(i, idx) = -1
659 end if
660 end do increment_chain
661
662 end do
663
664 end subroutine setup_chains
665
666
667 !> \brief Extract quantum numbers from raw multipole file name
668 !> \author J Benda
669 !> \date 2021
670 !>
671 !> Expect the multipole to be named "XXX-ab-(u,v,w)YYY.txt" and extract the characters 'a' and 'b' as well as the numbers
672 !> 'u', 'v' and 'w'.
673 !>
674 subroutine parse_file_name (filename, order, sph, ichain, i, l, m)
675
676 character(len=*), intent(in) :: filename
677 logical, intent(in) :: sph
678 integer, intent(in) :: order
679 integer, intent(out) :: ichain, i, l, m
680
681 character(len=1) :: c(order)
682 integer :: j, k, q(order), u, v
683
684 k = scan(filename, '(', back = .true.)
685
686 v = scan(filename(1:k-1), '-', back = .true.)
687 u = scan(filename(1:v-1), '-', back = .true.)
688
689 if (v - u /= order + 1) then
690 print '(3A,I0)', 'Name of the file "', filename, '" is not consistent with the given order ', order
691 stop 1
692 end if
693
694 do j = 1, order
695 c(j) = filename(k - 2 - order + j : k - 2 - order + j)
696 end do
697
698 do j = 1, order
699 if (sph) then
700 select case (c(j))
701 case ('m'); q(j) = -1
702 case ('0'); q(j) = 0
703 case ('p'); q(j) = +1
704 case default
705 print '(3A)', 'Dipole component "', c(j), '" is not valid in spherical basis.'
706 stop 1
707 end select
708 else
709 select case (c(j))
710 case ('y'); q(j) = -1
711 case ('z'); q(j) = 0
712 case ('x'); q(j) = +1
713 case default
714 print '(3A)', 'Dipole component "', c(j), '" is not valid in Cartesian basis.'
715 stop 1
716 end select
717 end if
718 end do
719
720 ichain = 1
721 do j = 1, order
722 ichain = 3*(ichain - 1) + q(j) + 2
723 end do
724
725 j = k + 1
726 k = j + scan(filename(j:), ',') - 1
727 read (filename(j : k - 1), *) i
728
729 j = k + 1
730 k = j + scan(filename(j:), ',') - 1
731 read (filename(j : k - 1), *) l
732
733 j = k + 1
734 k = j + scan(filename(j:), ')') - 1
735 read (filename(j : k - 1), *) m
736
737 end subroutine parse_file_name
738
739
740 !> \brief Read raw multipole from file
741 !> \author J Benda
742 !> \date 2021
743 !>
744 !> Read real and imaginary part of the raw multipole for all energies from the given file. The number of read elements
745 !> is returned via the parameter "n", the values themselves via "buffer". If "buffer" is not allocated or is too short,
746 !> it will be reallocated by this subroutine.
747 !>
748 subroutine read_file_data (filename, n, buffer)
749
750 character(len=*), intent(in) :: filename
751 integer, intent(out) :: n
752 complex(real64), allocatable, intent(inout), optional :: buffer(:)
753
754 integer :: ierr, u, i
755 real(real64) :: re_d, im_d
756
757 open (newunit = u, file = filename, action = 'read', form = 'formatted', iostat = ierr)
758
759 if (ierr /= 0) then
760 print '(3A)', 'Failed to open file "', filename, '"'
761 stop 1
762 end if
763
764 ! first pass: count valid lines only
765 ierr = 0
766 n = 0
767 do while (ierr == 0)
768 read (u, *, iostat = ierr) re_d, im_d
769 if (ierr == 0) n = n + 1
770 end do
771
772 ! if no buffer was given, do not read the data
773 if (.not. present(buffer)) then
774 close (u)
775 return
776 end if
777
778 ! resize the buffer
779 if (allocated(buffer)) then
780 if (size(buffer) < n) then
781 deallocate (buffer)
782 end if
783 end if
784 if (.not. allocated(buffer)) then
785 allocate (buffer(n))
786 end if
787
788 rewind(u)
789
790 ! actually read the data now
791 do i = 1, n
792 read (u, *) re_d, im_d
793 buffer(i) = cmplx(re_d, im_d, real64)
794 end do
795
796 close (u)
797
798 end subroutine read_file_data
799
800
801 !> \brief Calculate multi-photon matrix elements by asymptotic approximation
802 !> \authors J Benda
803 !> \date 2024
804 !>
805 !> Use the provided matrix elements of order `ord` to calculate matrix elements of order `ord`+`ext`. The results are
806 !> returned in the same (reallocated) array. If `outdir` is given, write out the resulting matrix elements to that
807 !> directory.
808 !>
809 subroutine extend_order (ord, MM, chains, ext, Ek, wIR, target_states, echl, prop, maxl, outdir)
810
811 use coupling_obj_gbl, only: couplings_type
812 use multidip_asy, only: akkl
813 use multidip_params, only: pi
814
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(:, :)
822
823 complex(real64), allocatable :: M0(:, :, :, :), Apws(:, :), Aion(:, :)
824 integer, allocatable :: chains0(:, :)
825
826 type(couplings_type) :: cpl
827 character(len=1) :: cmptname(3) = ['y', 'z', 'x']
828 character(len=1024) :: filename, strchain
829
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
833
834 nesc = size(mm, 1)
835 ntarg = size(mm, 4)
836 order = ord
837 deir = merge(wir, -wir, ext > 0)
838
839 call cpl % prec_cgaunt(maxl)
840
841 allocate (apws(nesc, 0:maxl), aion(nesc, ntarg))
842
843 apws = 0
844 aion = 0
845
846 do iex = 1, abs(ext)
847
848 nchain0 = size(chains, 2)
849 order = order + 1
850
851 print '(/,a,i0,/)', 'Extending pathway to order ', order
852
853 call move_alloc(mm, m0)
854 call move_alloc(chains, chains0)
855 call setup_chains(order, nchain, chains)
856
857 allocate (mm(nesc, (maxl + 1)**2, nchain, ntarg))
858
859 mm = 0
860
861 do itarg = 1, ntarg
862 do l = 0, maxl
863 print '(2x,2(a,i0))', 'Precomputing Akkl factors for target ', itarg, ', and l = ', l
864 ! precompute asymptotic factors
865 !$omp parallel do schedule(dynamic) private(kappa, k, lambda, jtarg)
866 do ie = 1, nesc
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)
873 end do
874 do jtarg = 1, ntarg
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)
878 end do
879 end do
880 do m = -l, l
881 ipw = l*l + l + m + 1
882 ! continuum-continuum transition
883 do lambda = abs(l - 1), min(maxl, l + 1)
884 do mu = -lambda, lambda
885 jpw = lambda*lambda + lambda + mu + 1
886 do compt = -1, +1
887 gaunt = cpl % rgaunt(l, lambda, 1, m, mu, compt)
888 if (gaunt /= 0) then
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)
894 end do
895 end if
896 end do
897 end do
898 end do
899 ! ion-ion transition
900 do jtarg = 1, ntarg
901 do compt = -1, +1
902 qion = prop(target_states(itarg), target_states(jtarg), compt + 2)
903 if (qion /= 0) then
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)
908 end do
909 end if
910 end do
911 end do
912 end do
913 end do
914 end do
915
916 end do
917
918 if (len_trim(outdir % str) /= 0) then
919 print '(/,3a)', 'Writing extended partial-wave amplitudes to "', outdir % str, '"'
920 do itarg = 1, ntarg
921 do ichain = 1, size(mm, 3)
922 do l = 0, maxl
923 do m = -l, l
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)
930 close (u)
931 end do
932 end do
933 end do
934 end do
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)]
937 close (u)
938 end if
939
940 end subroutine extend_order
941
942
943 !> \brief Write results to file
944 !> \author J Benda
945 !> \date 2021 - 2024
946 !>
947 subroutine write_quadratic_dipoles (L, MM, prefix, suffix)
948
949 complex(real64), allocatable, intent(in) :: MM(:, :)
950 character(len=*), intent(in) :: prefix, suffix
951 integer, intent(in) :: L
952
953 character(len=200) :: filename
954 integer :: u, ie
955
956 write (filename, '(A,I0,3A)') trim(prefix), l, trim(suffix), '.txt'
957
958 print '(/,3A)', 'Writing M[XUV+IR]* M[XUV-IR] to file "', trim(filename), '"'
959
960 open (newunit = u, file = trim(filename), action = 'write', form = 'formatted')
961
962 do ie = 1, size(mm, 2)
963 write (u, '(2E25.15)') sum(mm(:, ie))
964 end do
965
966 close (u)
967
968 end subroutine write_quadratic_dipoles
969
970
971 !> \brief Molecular- and recoil-frame RABITT delays
972 !> \author J Benda
973 !> \date 2022 - 2024
974 !>
975 !> Calculate the interference term of the photoelectron ionization probability for the following configurations:
976 !> 1. If the polarization axis in the molecular frame is given, evalutes the distribution for all emission
977 !> directions provided by the arguments `theta` and `phi` (for molecular-frame observables). These are
978 !> written to files "rabitt-signal-mol-?.txt", one file per a given angle, one line per energy.
979 !> 2. If the polarization axis in the molecular frame is given, evalutes the emission angle-integrated RABITT
980 !> interference term. The emission angle input from the command line is not used. The results are
981 !> written to file "rabitt-signal-int-1.txt".
982 !> 3. If the polarization axis in the molecular frame is given, evaluates the distribution integrated around
983 !> the axis, for values of the polar angle `theta`. The values of `phi` are ignored. This is useful when
984 !> partially resolved recoil frame, where the recoil axis coincides with the main quantization axis (z).
985 !> The outputs are written to files "rabitt-signal-axs-?.txt", one file per a given angle, one line per energy.
986 !> 4. Finally, regardless of the specification of the polarization axis, evaluate the quantity integrated over
987 !> all possible linear polarization as well as over all azimuthal emission angles. This is useful for
988 !> recoil-frame quantities. The outputs are written to files "rabitt-signal-rec-?.txt", one file per a given angle,
989 !> one line per energy.
990 !>
991 !> Colinear polarization of XUV and IR fields is assumed.
992 !>
993 !> \param[in] maxl Highest angular momentum
994 !> \param[in] chains1 List of available absorption paths for first (conjugated) pathway
995 !> \param[in] chains2 List of available absorption paths for second (non-conugated) pathway
996 !> \param[in] ntarg Number of targets to consider
997 !> \param[in] nesc Number of scattering energies
998 !> \param[in] Mp Raw ionization matrix elements for the XUV+IR pathway (Cartesian basis)
999 !> \param[in] Mm Raw ionization matrix elements for the XUV-IR pathway (Cartesian basis)
1000 !> \param[in] axis Unit vector in direction of the XUV polarization
1001 !> \param[in] axisIR Unit vector in direction of the IR polarization
1002 !> \param[in] theta List of photoelectron emission polar angles (in degrees)
1003 !> \param[in] phi List of photoelectron emission azimuthal angles (in degrees)
1004 !>
1005 subroutine calculate_oriented_dipoles (maxl, chains1, chains2, ntarg, nesc, Mp, Mm, axis, axisIR, theta, phi)
1006
1007 use dipelm_defs, only: pi
1008 use dipelm_special_functions, only: a_re_sp_harm, a_sp_harm
1010
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(:, :, :, :)
1016
1017 real(real64), allocatable :: Xlm(:, :), Yl0(:, :), sins(:), coss(:)
1018 complex(real64), allocatable :: Qmol(:, :), Qint(:, :), Qaxs(:, :), Qrec(:, :), QM(:), Xvalues(:)
1019
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
1022
1023 ntheta = 0
1024 nphi = 0
1025
1026 if (allocated(theta)) ntheta = size(theta)
1027 if (allocated(phi)) nphi = size(phi)
1028
1029 nang = max(ntheta, nphi)
1030
1031 if (nang == 0) return
1032
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))
1035
1036 qmol = 0
1037 qint = 0
1038 qaxs = 0
1039 qrec = 0
1040
1041 ! precalculate angular functions
1042 do iang = 1, nang
1043 rtheta = 0
1044 rphi = 0
1045
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
1048
1049 call a_re_sp_harm(maxl, rtheta, rphi, xvalues)
1050 xlm(:, iang) = real(xvalues, real64) ! X_{lm}(theta, phi)
1051 deallocate (xvalues)
1052
1053 call a_sp_harm(maxl, rtheta, zero, xvalues)
1054 yl0(:, iang) = real(xvalues, real64) ! Y_{lm}(theta, 0)
1055 deallocate (xvalues)
1056
1057 sins(iang) = sin(rtheta)
1058 coss(iang) = cos(rtheta)
1059 end do
1060
1061 ! evaluate the interference terms
1062 do itg = 1, ntarg
1063 do l1 = 0, maxl
1064 do m1 = -l1, l1
1065 pw1 = l1*l1 + l1 + m1 + 1
1066 pw1a = l1*l1 + l1 + abs(m1) + 1
1067 do l2 = 0, maxl
1068 do m2 = -l2, l2
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)
1073 cax = 0
1074 cai = 0
1075 ncompt = 0
1076
1077 if (sum(axis**2) > 0 .and. sum(axisir**2) > 0) then
1078 ! product of oriented polarization unit vectors
1079 cax = 1
1080 do icomp = 1, size(chains1, 1)
1081 i1 = 1 + mod(chains1(icomp, c1) + 2, 3) ! m projection -> Cartesian index
1082 ncompt(i1) = ncompt(i1) + 1
1083 cax = cax * merge(axis(i1), axisir(i1), icomp == 1)
1084 end do
1085 do icomp = 1, size(chains2, 1)
1086 i2 = 1 + mod(chains2(icomp, c2) + 2, 3) ! m projection -> Cartesian index
1087 ncompt(i2) = ncompt(i2) + 1
1088 cax = cax * merge(axis(i2), axisir(i2), icomp == 1)
1089 end do
1090
1091 ! azimuthal integral over the product of polarization vectors (assume axis == axisIR)
1092 if (ncompt(1) == 0 .and. ncompt(2) == 0) cai = 2*pi ! zz, zzzz
1093 if (ncompt(1) == 2 .neqv. ncompt(2) == 2) cai = pi ! xx, yy, xxzz, yyzz
1094 if (ncompt(1) == 2 .and. ncompt(2) == 2) cai = pi/4 ! xxyy
1095 if (ncompt(1) == 4 .or. ncompt(2) == 4) cai = 3*pi/4 ! xxxx, yyyy
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))
1098 end if
1099
1100 ! angular average of product of polarization unit vectors
1101 cav = cartesian_vector_component_product_average([chains1(:, c1), chains2(:, c2)])
1102
1103 ! update the value of the RABITT interference term
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
1107 !$omp parallel do
1108 do iang = 1, nang
1109 if (cax /= 0) then
1110 qmol(:, iang) = qmol(:, iang) + qm * cax * xlm(pw1, iang) * xlm(pw2, iang)
1111 end if
1112 if (cax /= 0 .and. l1 == l2 .and. m1 == m2 .and. iang == 1) then
1113 qint(:, 1) = qint(:, 1) + qm * cax
1114 end if
1115 if (m1 == m2 .and. cai /= 0) then
1116 qaxs(:, iang) = qaxs(:, iang) + qm * cai * yl0(pw1a, iang) * yl0(pw2a, iang)
1117 end if
1118 if (m1 == m2 .and. cav /= 0) then
1119 qrec(:, iang) = qrec(:, iang) + qm * cav * yl0(pw1a, iang) * yl0(pw2a, iang)
1120 end if
1121 end do
1122 end if
1123 end do ! c2
1124 end do ! c1
1125 end do ! m2
1126 end do ! l2
1127 end do ! m1
1128 end do ! l1
1129 end do ! itg
1130
1131 ! write fixed-polarization results to files (one per emission direction)
1132 call write_to_file('rabitt-signal-mol-', qmol)
1133 call write_to_file('rabitt-signal-int-', qint)
1134 call write_to_file('rabitt-signal-axs-', qaxs)
1135
1136 ! write fully polarization-averaged results to files (one per emission direction)
1137 call write_to_file('rabitt-signal-rec-', qrec)
1138
1139 end subroutine calculate_oriented_dipoles
1140
1141
1142 !> \brief Read a column from the text file
1143 !> \authors J Benda
1144 !> \date 2024
1145 !>
1146 subroutine read_real_array (filename, array)
1147
1148 character(len=*), intent(in) :: filename
1149 real(real64), allocatable, intent(inout) :: array(:)
1150
1151 integer :: u, i, stat, nlines
1152
1153 nlines = 0
1154
1155 open (newunit = u, file = filename, action = 'read', form = 'formatted')
1156
1157 ! count lines first
1158 do
1159 read (u, *, iostat = stat)
1160 if (stat /= 0) exit
1161 nlines = nlines + 1
1162 end do
1163
1164 allocate (array(nlines))
1165
1166 rewind(u)
1167
1168 ! now read the data
1169 do i = 1, nlines
1170 read (u, *) array(i)
1171 end do
1172
1173 close (u)
1174
1175 end subroutine read_real_array
1176
1177
1178 !> \brief Write the interference term to file
1179 !> \author J Benda
1180 !> \date 2022
1181 !>
1182 !> Produce one text file per angular combination. Write the real and imaginary part of the interference term, one line
1183 !> per scattering energy.
1184 !>
1185 !> \param[in] stem Initial string to be used in the name of the file to write
1186 !> \param[in] Q Interference terms (number of energies times number fo angles)
1187 !>
1188 subroutine write_to_file (stem, Q)
1189
1190 character(len=*), intent(in) :: stem
1191 complex(real64), allocatable, intent(in) :: Q(:, :)
1192
1193 character(len=256) :: filename
1194 integer :: iang, iene, u
1195
1196 do iang = 1, size(q, 2)
1197 write (filename, '(A,I0,A)') stem, iang, '.txt'
1198 open (newunit = u, file = trim(filename), form = 'formatted')
1199 do iene = 1, size(q, 1)
1200 write (u, '(2E25.15)') q(iene, iang)
1201 end do
1202 close (u)
1203 end do
1204
1205 end subroutine write_to_file
1206
1207end program multidip_rabitt_delays
subroutine rabitt_main
Main program.
subroutine read_real_array(filename, array)
Read a column from the text file.
subroutine extend_order(ord, mm, chains, ext, ek, wir, target_states, echl, prop, maxl, outdir)
Calculate multi-photon matrix elements by asymptotic approximation.
subroutine read_raw_multipoles(order1, order2, sph, ntarg, maxl, nesc, target_states, chains1, chains2, xuv_plus_ir_filenames, xuv_minus_ir_filenames, m_xuv_plus_ir, m_xuv_minus_ir)
Read multipoles from disk.
subroutine write_quadratic_dipoles(l, mm, prefix, suffix)
Write results to file.
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.
subroutine parse_file_name(filename, order, sph, ichain, i, l, m)
Extract quantum numbers from raw multipole file name.
subroutine calculate_oriented_dipoles(maxl, chains1, chains2, ntarg, nesc, mp, mm, axis, axisir, theta, phi)
Molecular- and recoil-frame RABITT delays.
subroutine write_to_file(stem, q)
Write the interference term to file.
program multidip_rabitt_delays
Calculate RABITT delays from raw multipole elements.
subroutine setup_chains(order, nchain, chains)
Assemble absorption chains.
subroutine print_help
Print program usage information.
subroutine read_file_data(filename, n, buffer)
Read raw multipole from file.
Asymptotic approximation of multi-photon matrix elements.
I/O routines used by MULTIDIP.
subroutine read_target_properties(lutarg, prop, etarg)
Read ion transition dipoles.
Hard-coded parameters of MULTIDIP.
real(wp), parameter pi
integer, parameter nmaxphotons
The limit on number of photons is nested_cgreen_integ
Main MULTIDIP routines.
subroutine calculate_quadratic_dipole_sph(beta, l, maxl, chains1, chains2, ntarg, nesc, m1, m2, p)
Evaluate asymmetry parameter for given total L in the spherical basis.
subroutine calculate_quadratic_dipole_xyz(beta, l, maxl, chains1, chains2, ntarg, nesc, m1, m2)
Evaluate asymmetry parameter for given total L in the Cartesian basis.
subroutine convert_xyz_to_sph(m_xyz, m_sph, maxl, chains)
Change coordiantes.
Special functions and objects used by MULTIDIP.
real(wp) recursive function cartesian_vector_component_product_average(q)
Return Cartesian invariant.