laserfields
Fortran95 library to describe time-dependent laser pulses
Loading...
Searching...
No Matches
laserfields_module.f90
Go to the documentation of this file.
1! Copyright (c) 2012, Johannes Feist
2! licensed under the MIT open source license, see LICENSE file
3
5 use nrtype
6 implicit none
7 save
8
9 real(dp), parameter :: gaussian_time_cutoff_fwhm = 3.5d0
10 integer, parameter :: minimum_steps_per_laser_period = 75
11
12 !> Datatype describing a single laserfield, should usually be created through make_laserfield routine
13 type :: laserfield
14 !> The shape of the envelope, can be 'gaussianF', 'gaussianI', 'sin2', 'sin_exp', 'linear', 'linear2', 'readin'
15
16 !> - gaussianF, gaussianI: Gaussian pulses with form exp(-z t<sup>2</sup>) (see laserfield%duration doc for meaning of z)
17 !> - sin2: sin<sup>2</sup> envelope
18 !> - sin_exp: sin<sup>form_exponent</sup> envelope
19 !> - linear: linear rampon, then constant amplitude, then linear rampoff
20 !> - linear2: same as linear, but with sin<sup>2</sup> rampon/off
21 !> - readin: read numerical data from an input file and interpolate
22 character(len=30) :: form = ''
23 !> Only for form=='readin': file to read numerical data from
24 character(len=200) :: datafile = ''
25 !> If .true., describe the vector potential A(t) with the given envelope - E(t) will contain derivative terms.
26 !> This is often useful to make sure that A(-infty) = A(infty), a requirement for propagating fields.
27 logical :: is_vecpot = .false.
28 ! these are the input laserfields.in "convenient" units - W/cm^2, nm, as
29 !> peak intensity in W/cm<sup>2</sup>
30 real(dp) :: intensity_wcm2 = 0.d0
31 !> carrier wavelength in nm
32 real(dp) :: lambda_nm = 0.d0
33 !> peak time of envelope in as
34 real(dp) :: peak_time_as = 0.d0
35 !> duration in as - depending on the value of form, this has different meanings!
36
37 !> - gaussianF: FWHM of the field envelope
38 !> - gaussianI: FWHM of the intensity envelope
39 !> - sin2, sin_exp: total duration of pulse
40 !> - linear, linear2: time during which pulse has peak amplitude
41 !> - readin: ignored
42 real(dp) :: duration_as = 0.d0
43 !> Only relevant for form linear and linear2: duration of rampon/rampoff at beginning and end of pulse, in as
44 real(dp) :: rampon_as = 0.d0
45 !> Carrier-envelope phase (CEP), in multiples of &pi;.<br> phase_pi=0 corresponds to a pulse with sin(w (t-t<sub>peak</sub>)) oscillation.
46 real(dp) :: phase_pi = 0.d0
47 !> Only relevant for form sin_exp: exponent of envelope
48 real(dp) :: form_exponent = 1.d0
49 !> linear temporal chirp rate, in units of omega_0/as
50
51 !> &omega;(t) = &omega;<sub>0</sub> (1 + linear_chirp_rate_w0 (t-t<sub>peak</sub>))
52 !> e.g. for a value of 1.d-3, the frequency will change by &omega; over 1000 as.
53 !> Since the carrier wave should not have negative frequencies, you must take care that the chirp is not too large.
54 real(dp) :: linear_chirp_rate_w0as = 0.d0
55
56 ! these are "derived" parameters that should not be entered directly. they are all in atomic units
57 !> <b>Derived</b>: peak electric field strength in a.u.
58 real(dp) :: e0 = 0.d0
59 !> <b>Derived</b>: carrier angular frequency in a.u.
60 real(dp) :: omega = 0.d0
61 !> <b>Derived</b>: carrier period in a.u.
62 real(dp) :: tx = 0.d0
63 !> <b>Derived</b>: peak time of envelope in a.u.
64 real(dp) :: peak_time = 0.d0
65 !> <b>Derived</b>: duration in a.u.
66 real(dp) :: duration = 0.d0
67 !> <b>Derived</b>: rampon/rampoff in a.u.
68 real(dp) :: rampon = 0.d0
69
70 !> Numerical arrays to save the fields for interpolation for read-in fields.
71 !> also used for numerical integration of E(t) to obtain A(t) and Z(t) for is_vecpot=.false.
72 !> and numerical integration of A(t) to obtain Z(t) for is_vecpot=.true.
73 real(dp), dimension(:), allocatable :: tt, ee, aa, zz
74 end type laserfield
75
76 !> Global array saving the laserfields read from parameter files and added with add_laserfield
77 type(laserfield), dimension(100) :: all_laserfields
78 !> Number of laserfields in the global array all_laserfields
79 integer :: n_laserfields = 0
80
81 !> Make a new type(laserfield), either from parameters or reading from a datafile
83 module procedure make_laserfield_params
84 module procedure make_laserfield_datafile
85 end interface make_laserfield
86 private :: make_laserfield_params, make_laserfield_datafile
87 !> Return the electric field E(t). if called with a type(laserfield) argument,
88 !> gets E(t) for just that one field, otherwise gets sum of all fields in all_laserfields
89 interface get_el
90 module procedure laserfields_get_el
91 module procedure lf_get_el
92 end interface
93 private :: laserfields_get_el, lf_get_el
94 !> Return the vector potential A(t). if called with a type(laserfield) argument,
95 !> gets A(t) for just that one field, otherwise gets sum of all fields in all_laserfields
96 interface get_al
97 module procedure laserfields_get_al
98 module procedure lf_get_al
99 end interface
100 private :: laserfields_get_al, lf_get_al
101 !> Return the positive-frequency part of the electric field E^(+)(t).
102 !> if called with a type(laserfield) argument,
103 !> gets E^(+)(t) for just that one field, otherwise gets sum of all fields in all_laserfields
105 module procedure laserfields_get_el_posfreq
106 module procedure lf_get_el_posfreq
107 end interface
108 private :: laserfields_get_el_posfreq, lf_get_el_posfreq
109 !> Return the positive-frequency part of the vector potential A^(+)(t).
110 !> if called with a type(laserfield) argument,
111 !> gets A^(+)(t) for just that one field, otherwise gets sum of all fields in all_laserfields
113 module procedure laserfields_get_al_posfreq
114 module procedure lf_get_al_posfreq
115 end interface
116 private :: laserfields_get_al_posfreq, lf_get_al_posfreq
117 !> Return the free-space displacement Z(t) of an electron. if called with a type(laserfield) argument,
118 !> gets Z(t) for just that one field, otherwise gets sum of all fields in all_laserfields
119 interface get_zl
120 module procedure laserfields_get_zl
121 module procedure lf_get_zl
122 end interface
123 private :: laserfields_get_zl, lf_get_zl
124 !> Return the fourier transform \f$ \tilde E(\omega) = 1/\sqrt{2\pi} \int \exp(-i\omega t) E(t) \mathrm{d}t\f$.
125 !> if called with a type(laserfield) argument, gets \f$\tilde E(\omega)\f$ for just that one field, otherwise gets sum of all fields in all_laserfields
127 module procedure laserfields_get_el_fourier_transform
128 module procedure lf_get_el_fourier_transform
129 end interface
130 private :: laserfields_get_el_fourier_transform, lf_get_el_fourier_transform
131 !> Return the fourier transform \f$ \tilde A(\omega) = 1/\sqrt{2\pi} \int \exp(-i\omega t) A(t) \mathrm{d}t = i\tilde E(\omega)/\omega\f$.
132 !> if called with a type(laserfield) argument, gets \f$\tilde A(\omega)\f$ for just that one field, otherwise gets sum of all fields in all_laserfields
134 module procedure laserfields_get_al_fourier_transform
135 module procedure lf_get_al_fourier_transform
136 end interface
137 private :: laserfields_get_al_fourier_transform, lf_get_al_fourier_transform
138 !> Return the fourier transform E(&omega;) as a string that can be used as a function in gnuplot.
139 !> if called with a type(laserfield) argument,
140 !> gets E(&omega;) for just that one field, otherwise gets sum of all fields in all_laserfields
142 module procedure laserfields_get_el_fourier_transform_string
143 module procedure lf_get_el_fourier_transform_string
144 end interface
145 private :: laserfields_get_el_fourier_transform_string, lf_get_el_fourier_transform_string
146
147contains
148 !---------------------------------------------------------------------------
149 !> add a type(laserfield) to the global list all_laserfields
150 subroutine add_laserfield(lf)
151 type(laserfield), intent(in) :: lf
152 if (n_laserfields == size(all_laserfields)) stop 'ERROR: added too many laser fields!'
155 end subroutine add_laserfield
156 !---------------------------------------------------------------------------
157 !> make a new type(laserfield). for the meaning of the parameter see the documentation of laserfield
158 type(laserfield) function make_laserfield_params(form,intensity_wcm2,lambda_nm,peak_time_as,&
159 duration_as,rampon_as,form_exponent,phase_pi,is_vecpot,linear_chirp_rate_w0as) result(lf)
160 character(len=*), intent(in) :: form
161 real(dp), intent(in) :: intensity_wcm2
162 real(dp), intent(in) :: lambda_nm
163 real(dp), intent(in) :: peak_time_as
164 real(dp), intent(in) :: duration_as
165 real(dp), intent(in), optional :: rampon_as, phase_pi, form_exponent, linear_chirp_rate_w0as
166 logical, intent(in), optional :: is_vecpot
167
168 lf%form = form
169 lf%intensity_Wcm2 = intensity_wcm2
170 lf%lambda_nm = lambda_nm
171 lf%peak_time_as = peak_time_as
172 lf%duration_as = duration_as
173 if (present(form_exponent)) lf%form_exponent = form_exponent
174 if (present(rampon_as)) lf%rampon_as = rampon_as
175 if (present(phase_pi)) lf%phase_pi = phase_pi
176 if (present(is_vecpot)) lf%is_vecpot = is_vecpot
177 if (present(linear_chirp_rate_w0as)) lf%linear_chirp_rate_w0as = linear_chirp_rate_w0as
178
180 end function make_laserfield_params
181 !---------------------------------------------------------------------------
182 type(laserfield) function make_laserfield_datafile(datafile,is_vecpot) result(lf)
183 character(len=*), intent(in) :: datafile
184 logical, intent(in), optional :: is_vecpot
185
186 lf%form = 'readin'
187 lf%datafile = datafile
188 if (present(is_vecpot)) lf%is_vecpot = is_vecpot
190 end function make_laserfield_datafile
191 !---------------------------------------------------------------------------
193 use atomic_units
194 type(laserfield), intent(inout) :: lf
195
196 ! make sure we know how to deal with this laser field
197 select case (lf%form)
198 case('gaussianF','gaussianI','linear','linear2','sin2','sin_exp','readin')
199 continue
200 case default
201 write(0,'(2A)') 'ERROR! laser field form unknown, form = ', trim(lf%form)
202 stop 516
203 end select
204
205 ! for laser fields that we read from file, all the parameters apart from is_vecpot
206 ! are undefined at first, and we have to infer them from the file that we read in
207 if (lf%form == 'readin') then
209 end if
210
211 lf%E0 = sqrt(lf%intensity_Wcm2 * au_wcm2toel2)
212 lf%TX = lf%lambda_nm * au_nm / au_c
213 if (lf%TX/=0) then
214 lf%omega = twopi / lf%TX
215 else ! special provision: if lambda=0, we take a laser field without any oscillation, so also omega=0
216 lf%omega = 0
217 end if
218 lf%peak_time = lf%peak_time_as * au_as
219 lf%duration = lf%duration_as * au_as
220 lf%rampon = lf%rampon_as * au_as
221
222 ! handle exceptions and warnings
223 if (lf%is_vecpot) then
224 select case (lf%form)
225 case('linear')
226 write(0,*) 'ERROR: envelope ''linear'' cannot be used with is_vecpot=true, as the E-field would be discontinuous.'
227 stop 311
228 case('sin_exp')
229 if (lf%form_exponent <= 1.d0) then
230 write(0,*) 'ERROR: envelope ''sin_exp'' with is_vecpot=true requires form_exponent > 1 for continuous E-field.'
231 write(0,*) ' form_exponent = ', lf%form_exponent
232 stop 312
233 end if
234 end select
235 end if
236
237 select case (lf%form)
238 case('linear','linear2')
239 if (lf%linear_chirp_rate_w0as /= 0.d0) then
240 write(0,'(3A)') 'WARNING: be careful with chirped laser pulses with ', trim(lf%form), &
241 & ' envelopes! Check that E(t) and A(t) are really as you expect them!'
242 end if
243 end select
244
245 if (lf%omega==0 .and. lf%linear_chirp_rate_w0as/=0) then
246 write(0,'(A)') 'WARNING: laserfield has lambda=0, i.e. no oscillation, but chirp/=0. chirp will be ignored!'
247 end if
248
249 if (lf%omega==0 .and. lf%is_vecpot) then
250 write(0,'(2A)') 'WARNING: laserfield has lambda=0, i.e. no oscillation, but is_vecpot is true. ', &
251 & 'The peak intensity is currently not treated correctly!'
252 end if
253
254 end subroutine laserfield_set_dependent
255 !---------------------------------------------------------------------------
258 use atomic_units
259 type(laserfield), intent(inout) :: lf
260 integer :: ii, io_error, unit, npoints
261 character(len=200) :: tmpstr
262 real(dp), dimension(:), allocatable :: tmptt, tmpvals
263 real(dp) :: dt, lastzerocrossing, starttime, endtime
264
265 write(6,*) '# Reading laserfield from file: ', trim(lf%datafile)
266
267 unit = get_unused_unit()
268 open(unit,file=trim(lf%datafile),status='old',action='read',iostat=io_error)
269 if (io_error /= 0) then
270 write(0,*) 'ERROR opening file for laserfield, filename =', trim(lf%datafile)
271 stop 511
272 end if
273
274 npoints=0
275 ! count number of valid lines in file
276 do while (io_error==0) ! read lines until an IO error ocurs, i.e. (normally) EOF
277 read(unit,'(a200)',iostat=io_error) tmpstr
278 tmpstr = adjustl(tmpstr)
279 ! at a comment, empty line or end of file, cycle the loop
280 if (tmpstr(1:1)=='#' .or. tmpstr=='' .or. io_error/=0) cycle
281 ! otherwise, the line has data
282 npoints=npoints+1
283 end do
284
285 if (npoints == 0) then
286 write(0,*) 'ERROR: No data points found in file for laserfield. Stop.'
287 stop 512
288 end if
289
290 write(6,*) '# Number of data points found:', npoints
291 allocate(tmptt(npoints), tmpvals(npoints))
292
293 ! now read in
294 ii = 0
295 rewind(unit, iostat=io_error)
296 do while (io_error==0)
297 read(unit,'(a200)',iostat=io_error) tmpstr
298 tmpstr = adjustl(tmpstr)
299 if (tmpstr(1:1)=='#' .or. tmpstr=='' .or. io_error/=0) cycle
300
301 ii = ii + 1
302 read(tmpstr,*) tmptt(ii), tmpvals(ii)
303 end do
304 close(unit)
305
306 !**************
307 ! analyze the data we have read to guess some information about the field
308 starttime = tmptt(1)
309 endtime = tmptt(npoints)
310
311 lf%TX = huge(1.d0)
312 dt = huge(1.d0)
313 lastzerocrossing = starttime
314 do ii = 2, npoints
315 if (tmptt(ii)<=tmptt(ii-1)) then
316 write(0,*) 'ERROR: times in data file for laser field must be monotonously increasing! filename =', trim(lf%datafile)
317 stop 514
318 end if
319
320 dt = min(dt,tmptt(ii)-tmptt(ii-1))
321 if (sign(1.d0,tmpvals(ii))/=sign(1.d0,tmpvals(ii-1))) then
322 ! we have crossed a zero, estimate TX with this
323 lf%TX = min(lf%TX,2*(tmptt(ii)-lastzerocrossing))
324 lastzerocrossing = tmptt(ii)
325 end if
326 end do
327
328 ! ensure small enough dt to allow for good interpolation and numeric integration/differentiation
329 ! note that TX will usually be much smaller than the "real" TX already, so this should
330 ! be small enough by far
331 dt = min(dt,lf%TX/200)
332
333 !**************
334 ! transform the field with arbitrary times to a grid with equal spacing for the time steps
335 ! watch out, we are reusing npoints
336 npoints = nint((endtime - starttime) / dt) + 1 ! the "+ 1" is for the endpoint
337 ! this is the actual dt we use to have exactly npoints from starttime to endtime
338 dt = (endtime - starttime) / (npoints-1)
339 allocate(lf%tt(npoints), lf%EE(npoints), lf%AA(npoints), lf%ZZ(npoints))
340 do ii = 1, npoints
341 lf%tt(ii) = starttime + (ii-1) * dt
342 end do
343
344 ! Interpolate to get laser field on regularly spaced points
345 if (lf%is_vecpot) then
346 lf%AA(:) = interpolate(tmptt,tmpvals,lf%tt,degree=6)
348 else
349 lf%EE(:) = interpolate(tmptt,tmpvals,lf%tt,degree=6)
351 end if
353
354 ! set guessed parameters
355 lf%E0 = maxval(abs(lf%EE))
356 lf%intensity_Wcm2 = lf%E0**2 / au_wcm2toel2
357 lf%omega = twopi / lf%TX
358 lf%lambda_nm = lf%TX / au_nm * au_c
359 lf%peak_time = (starttime + endtime) / 2
360 lf%peak_time_as = lf%peak_time / au_as
361 lf%duration = endtime - starttime
362 lf%duration_as = lf%duration / au_as
363
364 end subroutine read_laserfield_from_file
365 !---------------------------------------------------------------------------
367 type(laserfield), intent(inout) :: lf
368 real(dp) :: dt, zeit
369 integer :: ii
370
371 ! we already have A(t) for the laser field and want to calculate lf%EE = -dA/dt
372
373 ! use a smaller dt than the grid on which A(t) is given
374 dt = (lf%tt(2) - lf%tt(1))/50
375
376 do ii = 1, size(lf%tt)
377 zeit = lf%tt(ii)
378 ! do not forget the minus sign!
379 lf%EE(ii) = -(get_al(lf,zeit+dt) - get_al(lf,zeit-dt)) / (2*dt)
380 end do
381
383 !---------------------------------------------------------------------------
385 type(laserfield), intent(inout) :: lf
386 integer :: ii, jj, nsteps, simpson_fac
387 real(dp) :: EL, zeit
388 ! we have a laser field where we can get the electric field and
389 ! want to numerically integrate that to get the vector potential A(t) = -Int E(t) dt
390 ! we use the composite Simpson rule
391
392 ! nsteps HAS to be ODD for Simpson rule, so that the number of intervals is even
393 nsteps = 21
394
395 ! initialize first value to zero
396 lf%AA(1) = 0.d0
397 do ii = 2, size(lf%AA)
398 ! for each step we want to take, we do nsteps integration steps with the trapezoid rule
399 zeit = lf%tt(ii-1)
400 el = get_el(lf,zeit)
401
402 ! do integration from tt(ii-1) to tt(ii)
403 ! Int_a^b f(t) dt ~ (f(a) + 4*f(a+h) + 2*f(a+2*h) + 4*f(a+3*h) + ... + 4*f(b-h) + f(b)) * h/3
404 ! where h = (b-a)/(nsteps-1)
405 lf%AA(ii) = -el
406 simpson_fac = 4
407 do jj = 2, nsteps-1
408 zeit = (lf%tt(ii-1) * (nsteps-jj) + lf%tt(ii) * (jj-1)) / (nsteps-1)
409 ! jj = 1 -> zeit = lf%tt(ii-1) * (nsteps-1) / (nsteps-1) -> lf%tt(ii-1) -> ok
410 ! jj = nsteps -> zeit = lf%tt(ii) * (nsteps-1) / (nsteps-1) -> lf%tt(ii) -> ok
411 el = get_el(lf,zeit)
412 ! do not forget the minus sign!
413 lf%AA(ii) = lf%AA(ii) - simpson_fac * el
414 ! 6 - 2 = 4, 6 - 4 = 2 -> alternating between 4 and 2
415 simpson_fac = 6 - simpson_fac
416 end do
417 ! last step
418 zeit = lf%tt(ii)
419 el = get_el(lf,zeit)
420 lf%AA(ii) = lf%AA(ii) - el
421 ! int = sum(...) * h/3
422 lf%AA(ii) = lf%AA(ii) * (lf%tt(ii)-lf%tt(ii-1))/(3*(nsteps-1))
423 ! A(t+dt) = A(t) - Int_t^{t+dt} E(t) dt
424 lf%AA(ii) = lf%AA(ii) + lf%AA(ii-1)
425 !write(60,'(99g25.12)') lf%tt(ii), lf%AA(ii)
426 end do
428 !---------------------------------------------------------------------------
430 type(laserfield), intent(inout) :: lf
431 integer :: ii, jj, nsteps, simpson_fac
432 real(dp) :: AL, zeit
433 ! we have a laser field where we can get the vector potential
434 ! want to numerically integrate that to get the classical position Z(t) = -Int A(t) dt
435 ! we use the composite Simpson rule
436
437 ! nsteps HAS to be ODD for Simpson rule, so that the number of intervals is even
438 nsteps = 21
439
440 ! initialize first value to zero
441 lf%ZZ(1) = 0.d0
442 do ii = 2, size(lf%ZZ)
443 ! for each step we want to take, we do nsteps integration steps with the trapezoid rule
444 zeit = lf%tt(ii-1)
445 al = get_al(lf,zeit)
446
447 ! do integration from tt(ii-1) to tt(ii)
448 ! Int_a^b f(t) dt ~ (f(a) + 4*f(a+h) + 2*f(a+2*h) + 4*f(a+3*h) + ... + 4*f(b-h) + f(b)) * h/3
449 ! where h = (b-a)/(nsteps-1)
450 lf%ZZ(ii) = -al
451 simpson_fac = 4
452 do jj = 2, nsteps-1
453 zeit = (lf%tt(ii-1) * (nsteps-jj) + lf%tt(ii) * (jj-1)) / (nsteps-1)
454 ! jj = 1 -> zeit = lf%tt(ii-1) * (nsteps-1) / (nsteps-1) -> lf%tt(ii-1) -> ok
455 ! jj = nsteps -> zeit = lf%tt(ii) * (nsteps-1) / (nsteps-1) -> lf%tt(ii) -> ok
456 al = get_al(lf,zeit)
457 ! do not forget the minus sign!
458 lf%ZZ(ii) = lf%ZZ(ii) - simpson_fac * al
459 ! 6 - 2 = 4, 6 - 4 = 2 -> alternating between 4 and 2
460 simpson_fac = 6 - simpson_fac
461 end do
462 ! last step
463 zeit = lf%tt(ii)
464 al = get_al(lf,zeit)
465 lf%ZZ(ii) = lf%ZZ(ii) - al
466 ! int = sum(...) * h/3
467 lf%ZZ(ii) = lf%ZZ(ii) * (lf%tt(ii)-lf%tt(ii-1))/(3*(nsteps-1))
468 ! Z(t+dt) = Z(t) - Int_t^{t+dt} A(t) dt
469 lf%ZZ(ii) = lf%ZZ(ii) + lf%ZZ(ii-1)
470 !write(60,'(99g25.12)') lf%tt(ii), lf%ZZ(ii)
471 end do
473 !---------------------------------------------------------------------------
475 type(laserfield), intent(inout) :: lf
476 integer :: ii, npoints
477 real(dp) :: starttime, endtime, dt
478 ! we have a laser field where we can get the electric field and
479 ! want to numerically integrate that to get the vector potential
480 ! we use the trapezoid rule
481
482 starttime = lf_get_starttime(lf)
483 endtime = lf_get_endtime(lf)
484 ! ensure small enough dt to allow for good interpolation
485 dt = lf%TX/250
486 if (dt == 0.d0) then
487 ! this is a field without oscillation - interpolate envelope with 500 points
488 dt = (endtime-starttime) / 500
489 end if
490
491 ! find number of points closest to wanted dt
492 npoints = nint((endtime-starttime) / dt + 1) ! the "+ 1" is for the endpoint
493 allocate(lf%tt(npoints), lf%AA(npoints))
494 do ii = 1, npoints
495 ! set the times through linear interpolation from starttime to endtime, without reference to dt
496 ! this avoids numerical addition problems if starttime is very large and dt is small
497 ! the actual time step is not exactly equal to dt, as "(endtime-starttime) / dt + 1" is not precisely integer
498 lf%tt(ii) = (starttime * (npoints-ii) + endtime * (ii-1)) / (npoints-1)
499 end do
500
502
503 end subroutine lf_setup_aa_interpolation
504 !---------------------------------------------------------------------------
506 type(laserfield), intent(inout) :: lf
507 integer :: ii, npoints
508 real(dp) :: starttime, endtime, dt
509 ! we have a laser field where we can get the vector potential and
510 ! want to numerically integrate that to get the classical position for the acceleration gauge / Kramers frame hamiltonian
511 ! we use the trapezoid rule
512
513 starttime = lf_get_starttime(lf)
514 endtime = lf_get_endtime(lf)
515 ! ensure small enough dt to allow for good interpolation
516 dt = lf%TX/250
517 if (dt == 0.d0) then
518 ! this is a field without oscillation - interpolate envelope with 500 points
519 dt = (endtime-starttime) / 500
520 end if
521
522 ! find number of points closest to wanted dt
523 npoints = nint((endtime-starttime) / dt + 1) ! the "+ 1" is for the endpoint
524 if (.not.allocated(lf%tt)) then
525 allocate(lf%tt(npoints))
526 else if (size(lf%tt)/=npoints) then
527 write(0,*) 'ERROR: size(lf%tt)/=npoints in lf_setup_ZZ_interpolation!'
528 stop 356
529 end if
530
531 allocate(lf%ZZ(npoints))
532 do ii = 1, npoints
533 ! set the times through linear interpolation from starttime to endtime, without reference to dt
534 ! this avoids numerical addition problems if starttime is very large and dt is small
535 ! the actual time step is not exactly equal to dt, as "(endtime-starttime) / dt + 1" is not precisely integer
536 lf%tt(ii) = (starttime * (npoints-ii) + endtime * (ii-1)) / (npoints-1)
537 end do
538
540
541 end subroutine lf_setup_zz_interpolation
542 !---------------------------------------------------------------------------
543 ! this calculates the envelope of the laser field
544 ! as well as the first derivative (by time) of the envelope
545 ! the derivative is needed for calculating E(t) = -dA/dt if the laserfield describes A(t) (lf%is_vecpot is .true.)
546 subroutine lf_get_envelope(lf,zeit,env,envpr)
547 type(laserfield), intent(in) :: lf
548 real(dp), intent(in) :: zeit
549 real(dp), intent(out) :: env, envpr
550 real(dp) :: trel, ttmp
551
552 trel = zeit - lf%peak_time
553
554 select case (lf%form)
555 case('gaussianF') ! laser pulse with Gaussian envelope, lf%duration is FWHM of electric field envelope
556 env = exp(-trel**2*log(16.d0)/lf%duration**2)
557 envpr = -2*trel*log(16.d0)/lf%duration**2 * env
558 case('gaussianI') ! laser pulse with Gaussian envelope, lf%duration is FWHM of intensity envelope
559 env = exp(-trel**2*log( 4.d0)/lf%duration**2)
560 envpr = -2*trel*log( 4.d0)/lf%duration**2 * env
561 case('linear')
562 ! "linear" is a field with constant intensity for lf%duration, and linear rampon/rampoff of duration lf%rampon at the beginning and end
563 if (abs(trel) < lf%duration/2) then
564 env = 1.d0
565 envpr = 0.d0
566 else if (abs(trel) < lf%duration/2 + lf%rampon) then
567 env = 1.d0 - (abs(trel)-lf%duration/2) / lf%rampon
568 envpr = -sign(1.d0,trel) / lf%rampon
569 else
570 env = 0.d0
571 envpr = 0.d0
572 end if
573 case('linear2')
574 ! same as linear, but with sin2 rampon/rampoff
575 if (abs(trel) < lf%duration/2) then
576 env = 1.d0
577 envpr = 0.d0
578 else if (abs(trel) < lf%duration/2 + lf%rampon) then
579 ttmp = 1.d0 - (abs(trel)-lf%duration/2) / lf%rampon
580 env = sin(pio2*ttmp)**2
581 envpr = -sign(1.d0,trel) * sin(pi*trel) * pio2/lf%rampon
582 else
583 env = 0.d0
584 envpr = 0.d0
585 end if
586 case ('sin2')
587 if (abs(trel) < lf%duration/2) then
588 env = cos(pi*trel/lf%duration)**2
589 ! 2 sin(wt) cos(wt) = sin(2wt)
590 envpr = -sin(twopi*trel/lf%duration) * pi/lf%duration
591 else
592 env = 0.d0
593 envpr = 0.d0
594 end if
595 case ('sin_exp')
596 if (abs(trel) < lf%duration/2) then
597 env = cos(pi*trel/lf%duration)**lf%form_exponent
598 envpr = -sin(pi*trel/lf%duration) * lf%form_exponent * &
599 & cos(pi*trel/lf%duration)**(lf%form_exponent-1) * pi/lf%duration
600 else
601 env = 0.d0
602 envpr = 0.d0
603 end if
604 case default
605 write(0,'(2A)') 'ERROR! laser field form unknown, form = ', trim(lf%form)
606 stop 516
607 end select
608
609 env = lf%E0 * env
610 envpr = lf%E0 * envpr
611
612 end subroutine lf_get_envelope
613 !---------------------------------------------------------------------------
614 complex(dpc) function lf_envelope_fourier(lf,omega) result(val)
615 use atomic_units
616 ! return the fourier transform of the envelope of the laser field
617 ! we write the whole pulse as
618 ! f(t) = (env(t) exp(IU*(phi0 + w0*tp + chirp*tp**2)) + c.c. ) / (2*IU), where tp = t-tpeak
619 ! for the fourier transform we include the chirp term exp(i chirp (t-tpeak)**2) in the envelope.
620 ! the fourier transform of the envelope is then a complex function.
621 ! however, for unchirped pulses, the result will be purely real!
622 type(laserfield), intent(in) :: lf
623 real(dp), intent(in) :: omega
624 real(dp) :: chirp
625 complex(dpc) :: z
626
627 ! important - use omega, not lf%omega as the argument here!!
628
629 ! instantaneous frequency:
630 ! w(t) = lf%omega * (1.d0 + lf%linear_chirp_rate_w0as/au_as * (zeit-lf%peak_time))
631 chirp = lf%omega * lf%linear_chirp_rate_w0as / au_as
632
633 ! for the various calculations, see chirped_fourier.nb in the mathematica subversion directory
634 select case (lf%form)
635 case('gaussianF')
636 ! F[exp(-z*t**2)] = exp(-w**2/4*z)/sqrt(2*z) (for real(z)>0)
637 z = log(16.d0)/lf%duration**2 - iu * chirp
638 val = exp(-omega**2/(4*z)) / sqrt(2*z)
639 case('gaussianI')
640 z = log( 4.d0)/lf%duration**2 - iu * chirp
641 val = exp(-omega**2/(4*z)) / sqrt(2*z)
642 case('linear')
643 if (chirp /= 0.d0) then
644 write(0,'(A)') 'ERROR! fourier transform of "linear" envelope with chirp not implemented!'
645 stop 676
646 end if
647 val = sqrt(8.d0/pi) * sin(omega*lf%rampon/2) * sin(omega*(lf%rampon+lf%duration)/2) / (lf%rampon * omega**2)
648 case('linear2')
649 if (chirp /= 0.d0) then
650 write(0,'(A)') 'ERROR! linear2 fourier transform with chirp not implemented!'
651 stop 676
652 end if
653 val = sqrt(2*pi**3) * cos(omega*lf%rampon/2) * sin(omega*(lf%rampon+lf%duration)/2) / (pi**2*omega - lf%rampon**2*omega**3)
654 case ('sin2')
655 if (chirp == 0.d0) then ! the expression with chirp can not be evaluated with chirp == 0, so we take this as a special case
656 val = sqrt(8.d0*pi**3) * sin(omega*lf%duration/2)/(twopi**2*omega - omega**3*lf%duration**2)
657 else
658 ! now we use that cos(pi*t/T)**2 * exp(i*c*t**2) can be written as 0.5 exp(i*c*t**2) + 0.25 exp(i*c*t**2 - 2*i*pi*t/T) + 0.25 exp(i*c*t**2 + 2*i*pi*t/T)
659 ! the integral of exp(IU*(a*t+b*t**2)) from t=-T/2 to t=T/2 can be calculated analytically and is implemented in the function below
660 ! the arguments are a={-omega, -2*pi/T-omega, 2*pi/T-omega} and b=chirp
661 val = expiatbt2_intt( - omega, chirp, lf%duration)/2 &
662 & + expiatbt2_intt(-twopi/lf%duration - omega, chirp, lf%duration)/4 &
663 & + expiatbt2_intt( twopi/lf%duration - omega, chirp, lf%duration)/4
664 end if
665 case ('sin_exp')
666 stop 'ERROR! sin_exp fourier transform too complicated to implement'
667 case default
668 stop 'ERROR! unknown laser field form'
669 end select
670
671 val = lf%E0 * val
672
673 end function lf_envelope_fourier
674 !---------------------------------------------------------------------------
675 ! returns the result of the integral Int(exp(IU*(a*t+b*t**2)),{t,-T/2,T/2}) / sqrt(TWOPI)
676 complex(dpc) function expiatbt2_intt(a,b,T) result(res)
677 use faddeeva, ONLY : erf
678 real(dp), intent(in) :: a, b, t
679 real(dp) :: at
680 complex(dpc) :: x1
681
682 if (abs(b*t**2) <= 1e-5) then
683 ! use first-order expansion for small b to avoid numerical errors
684 at = a * t
685 if (abs(at) < 1e-8) then
686 ! avoid numerical errors for small aT
687 res = (1 + iu/12 * b*t**2 - b*t**2/160) * t / sqrt(twopi)
688 end if
689 x1 = 2*iu * b / a**2
690 res = x1 * cos(at / 2) + (2 - 2*x1 + 0.5*iu * b*t**2) * sin(at / 2) / at
691 res = res * t / sqrt(twopi)
692 else
693 res = erf((a-b*t)/sqrt(4*iu*b)) - erf((a+b*t)/sqrt(4*iu*b))
694 res = res * (-iu/sqrt(8*iu*b)) * exp(-iu*a**2/(4*b))
695 end if
696 end function expiatbt2_intt
697 !---------------------------------------------------------------------------
698 character(1000) function lf_envelope_fourier_string(lf,omegastr) result(val)
699 use atomic_units
701 ! return the fourier transform of the envelope of the laser field
702 ! we write the whole pulse as
703 ! f(t) = (env(t) exp(IU*(phi0 + w0*tp + chirp*tp**2)) + c.c. ) / (2*IU), where tp = t-tpeak
704 ! for the fourier transform of the envelope, we include the chirp term
705 ! exp(i chirp (t-tpeak)**2) in the envelope.
706 ! the fourier transform is then a complex function.
707 ! however, for unchirped pulses, the result will be purely real!
708 type(laserfield), intent(in) :: lf
709 character(*), intent(in) :: omegastr
710 character(1000) :: tmpstr
711 real(dp) :: chirp
712 complex(dpc) :: z
713
714 ! important - use omega, not lf%omega as the argument here!!
715
716 ! instantaneous frequency:
717 ! w(t) = lf%omega * (1.d0 + lf%linear_chirp_rate_w0as/au_as * (zeit-lf%peak_time))
718 chirp = lf%omega * lf%linear_chirp_rate_w0as / au_as
719
720 ! for the various calculations, see chirped_fourier.nb in the mathematica subversion directory
721
722 select case (lf%form)
723 case('gaussianF')
724 ! F[exp(-z*t**2)] = exp(-w**2/4*z)/sqrt(2*z) (for real(z)>0)
725 z = log(16.d0)/lf%duration**2 - iu * chirp
726 write(tmpstr,'(999A)') gnuplotstring(1/sqrt(2*z)), ' * exp(', gnuplotstring(-1/(4*z)),' * ('//omegastr//')**2)'
727 case('gaussianI')
728 z = log( 4.d0)/lf%duration**2 - iu * chirp
729 write(tmpstr,'(999A)') gnuplotstring(1/sqrt(2*z)), ' * exp(', gnuplotstring(-1/(4*z)),' * ('//omegastr//')**2)'
730 case('linear')
731 if (chirp /= 0.d0) then
732 write(0,'(A)') 'ERROR! fourier transform of "linear" envelope with chirp not implemented!'
733 stop 676
734 end if
735 write(tmpstr,'(SP,999(ES15.8,A))') 8.d0/(pi*lf%rampon), ' * sin(', lf%rampon/2,'*('//omegastr//')) * sin(', &
736 & (lf%rampon+lf%duration)/2,'*('//omegastr//')) / ('//omegastr//')**2'
737 case('linear2')
738 if (chirp /= 0.d0) then
739 write(0,'(A)') 'ERROR! linear2 fourier transform with chirp not implemented!'
740 stop 676
741 end if
742 write(tmpstr,'(SP,999(ES15.8,A))') sqrt(2*pi**3), ' * cos(', lf%rampon/2,'*('//omegastr//')) * sin(', &
743 & (lf%rampon+lf%duration)/2,'*('//omegastr//')) / (',pi**2,'*('//omegastr//') - ',lf%rampon**2,'*('//omegastr//')**3)'
744 case ('sin2')
745 if (chirp == 0.d0) then ! the expression with chirp can not be evaluated with chirp == 0, so we take this as a special case
746 write(tmpstr,'(SP,999(ES15.8,A))') sqrt(8*pi**3), ' * sin(',lf%duration/2,'*('//omegastr//')) / (', &
747 & twopi**2,'*('//omegastr//') - ',lf%duration**2,'*('//omegastr//')**3)'
748 else
749 write(0,'(A)') 'ERROR! sin2 fourier transform function string with chirp not implemented!'
750 stop 676
751 end if
752 case ('sin_exp')
753 write(0,'(2A)') 'ERROR! sin_exp fourier transform too complicated to implement'
754 stop 517
755 case default
756 write(0,'(2A)') 'ERROR! laser field form unknown, form = ', trim(lf%form)
757 stop 518
758 end select
759
760 ! multiply with sqrt(2.) to get normalisation such that integral
761 ! over omega from 0 to infinity gives the total power in the laser field
762 ! (same as integral over t from -infinity to infinity)
763 ! as the field E(t) is real, we know that E(omega) is symmetric about 0
764 write(val,'(SP,A,ES15.8,3A)') '(',lf%E0,' * ',trim(tmpstr),')'
765
766 end function lf_envelope_fourier_string
767 !---------------------------------------------------------------------------
768 subroutine lf_get_omega(lf,zeit,omega,env)
769 ! Calculate current frequency (which changes with time when a chirp rate is specified)
770 ! returns with an error if omega is 0 or smaller
771 ! optional argument env can be given to suppress this error when env (laser field envelope) is smaller than epsilon
772 use atomic_units
773 type(laserfield), intent(in) :: lf
774 real(dp), intent(in) :: zeit
775 real(dp), intent(out) :: omega
776 real(dp), intent(inout), optional :: env
777
778 ! The chirp rate is given in omega_0/as
779 omega = lf%omega * (1.d0 + lf%linear_chirp_rate_w0as/au_as * (zeit-lf%peak_time))
780 ! if omega is larger than or equal to zero, everything is okay and we can return
781 if (omega >= 0.d0) return
782
783 ! omega < 0.d0 -> check envelope if present
784 if (present(env)) then
785 if (env <= epsilon(1.d0)) then
786 ! envelope <= epsilon, recover by setting envelope to ZERO
787 env = 0.d0
788 ! now we can return. we do not write error message to prevent flooding e.g. fourierlaserfield output
789 return
790 end if
791 end if
792
793 ! omega < 0.d0 and no envelope or envelope too large
794 write(0,'(a)') ' ERROR: Field chirp is too large, omega(t) <= zero!'
795 write(0,'(a,9g15.5)') ' t, omega = ', zeit, omega
796 if (present(env)) write(0,'(a,9g15.5)') ' envelope > epsilon, env, epsilon =', env, epsilon(1.d0)
797 write(0,*) 'STOPPING!'
798 stop 519
799
800 end subroutine lf_get_omega
801 !---------------------------------------------------------------------------
802 real(dp) function lf_get_el(lf,zeit,env_out) result(el)
804 type(laserfield), intent(in) :: lf
805 real(dp), intent(in) :: zeit
806 real(dp), intent(out), optional :: env_out
807 real(dp) :: env, envpr, osc, oscpr
808 real(dp) :: omega
809
810 if (lf%form == 'readin') then
811 if (zeit < lf%tt(1) .or. zeit > lf%tt(size(lf%tt))) then
812 el = 0.d0
813 else
814 ! interpolate a value and cycle to next laser field
815 el = interpolate(lf%tt,lf%EE,zeit,degree=6)
816 end if
817 ! set the envelope part to zero, as the readin files can not make this distinction
818 env = 0.d0
819 else
820 call lf_get_envelope(lf,zeit,env,envpr)
821
822 if (lf%omega==0) then ! No oscillation enclosed by envelope
823 if (lf%is_vecpot) then
824 el = -envpr
825 else
826 el = env
827 end if
828 else
829 call lf_get_omega(lf,zeit,omega,env)
830 osc = sin(omega * (zeit-lf%peak_time) + pi*lf%phase_pi)
831 ! d(w(t)*(t-peak))/dt = w(t) + w'(t)*(t-peak) = omega + lf%omega * lf%chirp * (t-peak) = 2 * omega - lf%omega
832 oscpr = (2.d0*omega-lf%omega)*cos(omega*(zeit-lf%peak_time)+pi*lf%phase_pi)
833
834 if (lf%is_vecpot) then
835 ! Divide out derivative of oscillation to ensure peak amplitude of E0
836 ! NOTE: this does not actually give a peak amplitude of E0 for chirped linear/linear2 pulses
837 el = -(env * oscpr + envpr * osc) / lf%omega
838 else ! describes electric field directly
839 el = env * osc
840 end if
841 end if
842 end if
843
844 if (present(env_out)) env_out = env
845
846 end function lf_get_el
847 !---------------------------------------------------------------------------
848 real(dp) function lf_get_al(lf,zeit,env_out) result(al)
850 type(laserfield), intent(inout) :: lf
851 real(dp), intent(in) :: zeit
852 real(dp), intent(out), optional :: env_out
853 real(dp) :: env, envpr, osc
854 real(dp) :: omega
855
856 if (lf%form == 'readin' .or. (.not.lf%is_vecpot)) then
857 ! setup lf%AA/lf%tt if it does not already exist
858 if (.not.allocated(lf%AA)) call lf_setup_aa_interpolation(lf)
859
860 if (zeit < lf%tt(1)) then
861 al = 0.d0
862 else if (zeit > lf%tt(size(lf%tt))) then
863 ! AL (should be zero after pulse for propagating pulse!) does not change after end of pulse
864 al = lf%AA(size(lf%AA))
865 else
866 ! interpolate a value from the numerical array lf%AA
867 al = interpolate(lf%tt,lf%AA,zeit,degree=6)
868 end if
869
870 ! set the envelope part to zero, as the readin files can not make this distinction
871 env = 0.d0
872 else
873 call lf_get_envelope(lf,zeit,env,envpr)
874
875 if (lf%omega==0) then ! No oscillation enclosed by envelope
876 al = env
877 else
878 call lf_get_omega(lf,zeit,omega,env)
879 osc = sin(omega * (zeit-lf%peak_time) + pi*lf%phase_pi)
880 ! Divide out derivative of oscillation to ensure peak amplitude of E0 for electric field
881 al = env*osc / lf%omega
882 end if
883 end if
884 if (present(env_out)) env_out = env
885 end function lf_get_al
886 !---------------------------------------------------------------------------
887 complex(dpc) function lf_get_el_posfreq(lf,zeit,env_out) result(ELp)
889 type(laserfield), intent(in) :: lf
890 real(dp), intent(in) :: zeit
891 real(dp), intent(out), optional :: env_out
892 real(dp) :: env, envpr
893 real(dp) :: omega
894 complex(dpc) :: osc, oscpr
895
896 if (lf%form == 'readin') then
897 stop 'ERROR: positive-frequency decomposition not implemented for readin laser fields'
898 else
899 call lf_get_envelope(lf,zeit,env,envpr)
900
901 if (lf%omega==0) then ! No oscillation enclosed by envelope
902 elp = env / 2.d0
903 else
904 call lf_get_omega(lf,zeit,omega,env)
905 osc = iu/2 * exp(-iu * (omega*(zeit-lf%peak_time) + pi*lf%phase_pi))
906
907 if (lf%is_vecpot) then
908 ! d(phase)/dt = 2*omega - lf%omega
909 oscpr = (2.d0*omega-lf%omega) * (-iu * osc)
910 elp = -(env * oscpr + envpr * osc) / lf%omega
911 else ! describes electric field directly
912 elp = env * osc
913 end if
914 end if
915 end if
916
917 if (present(env_out)) env_out = env
918 end function lf_get_el_posfreq
919 !---------------------------------------------------------------------------
920 complex(dpc) function lf_get_al_posfreq(lf,zeit,env_out) result(ALp)
921 type(laserfield), intent(in) :: lf
922 real(dp), intent(in) :: zeit
923 real(dp), intent(out), optional :: env_out
924 real(dp) :: env, envpr
925 real(dp) :: omega
926 complex(dpc) :: osc
927
928 if (lf%form == 'readin') then
929 stop 'ERROR: positive-frequency decomposition not implemented for readin laser fields'
930 end if
931 if (.not.lf%is_vecpot) then
932 stop 'ERROR: laser field is not given as a vector potential, cannot get positive-frequency A(t) analytically!'
933 end if
934
935 call lf_get_envelope(lf,zeit,env,envpr)
936
937 if (lf%omega==0) then ! No oscillation enclosed by envelope
938 alp = env / 2.d0
939 else
940 call lf_get_omega(lf,zeit,omega,env)
941 osc = iu/2 * exp(-iu * (omega*(zeit-lf%peak_time) + pi*lf%phase_pi))
942 ! Divide out derivative of oscillation to ensure peak amplitude of E0 for electric field
943 alp = env * osc / lf%omega
944 end if
945
946 if (present(env_out)) env_out = env
947 end function lf_get_al_posfreq
948 !---------------------------------------------------------------------------
949 real(dp) function lf_get_zl(lf,zeit) result(zl)
951 type(laserfield), intent(inout) :: lf
952 real(dp), intent(in) :: zeit
953 integer :: np
954 if (.not.allocated(lf%ZZ)) call lf_setup_zz_interpolation(lf)
955 np = size(lf%tt)
956 if (zeit < lf%tt(1)) then
957 zl = 0.d0
958 else if (zeit > lf%tt(np)) then
959 ! ZL changes linearly after end of pulse (usually AL(endtime) should be zero, so ZL stays constant)
960 zl = lf%ZZ(np) - (zeit - lf%tt(np)) * get_al(lf,lf%tt(np))
961 else
962 ! interpolate a value from the numerical array lf%ZZ
963 zl = interpolate(lf%tt,lf%ZZ,zeit,degree=6)
964 end if
965 end function lf_get_zl
966 !---------------------------------------------------------------------------
967 real(dp) function laserfields_get_el(zeit,envarr,partarr) result(el)
968 real(dp), intent(in) :: zeit
969 real(dp), dimension(n_laserfields), intent(out), optional :: envarr, partarr
970 integer :: i_field
971 real(dp) :: env, part
972
973 el = 0.d0
974 if (present(envarr)) envarr = 0.d0
975 if (present(partarr)) partarr = 0.d0
976
977 do i_field = 1, n_laserfields
978 part = get_el(all_laserfields(i_field),zeit,env)
979 el = el + part
980 if (present(envarr)) envarr(i_field) = env
981 if (present(partarr)) partarr(i_field) = part
982 end do
983
984 end function laserfields_get_el
985 !---------------------------------------------------------------------------
986 real(dp) function laserfields_get_al(zeit,envarr,partarr) result(al)
987 real(dp), intent(in) :: zeit
988 real(dp), dimension(n_laserfields), intent(out), optional :: envarr, partarr
989 integer :: i_field
990 real(dp) :: env, part
991
992 al = 0.d0
993 do i_field = 1, n_laserfields
994 part = get_al(all_laserfields(i_field),zeit,env)
995 al = al + part
996 if (present(envarr)) envarr(i_field) = env
997 if (present(partarr)) partarr(i_field) = part
998 end do
999 end function laserfields_get_al
1000 !---------------------------------------------------------------------------
1001 complex(dpc) function laserfields_get_el_posfreq(zeit) result(ELp)
1002 real(dp), intent(in) :: zeit
1003 integer :: i_field
1004
1005 elp = 0
1006 do i_field = 1, n_laserfields
1007 elp = elp + get_el_posfreq(all_laserfields(i_field),zeit)
1008 end do
1009
1010 end function laserfields_get_el_posfreq
1011 !---------------------------------------------------------------------------
1012 complex(dpc) function laserfields_get_al_posfreq(zeit) result(ALp)
1013 real(dp), intent(in) :: zeit
1014 integer :: i_field
1015
1016 alp = 0
1017 do i_field = 1, n_laserfields
1018 alp = alp + get_al_posfreq(all_laserfields(i_field),zeit)
1019 end do
1020 end function laserfields_get_al_posfreq
1021 !---------------------------------------------------------------------------
1022 real(dp) function laserfields_get_zl(zeit) result(zl)
1023 real(dp), intent(in) :: zeit
1024 integer :: i_field
1025 zl = 0.d0
1026 do i_field = 1, n_laserfields
1027 zl = zl + get_zl(all_laserfields(i_field),zeit)
1028 end do
1029 end function laserfields_get_zl
1030 !---------------------------------------------------------------------------
1031 real(dp) function lf_get_halftotaltime(lf) result(tt)
1032 type(laserfield), intent(in) :: lf
1033 select case (lf%form)
1034 case('gaussianF')
1035 ! for gaussian, take peak_time + fwhm*gaussian_time_cutoff_fwhm as cutoff
1036 tt = lf%duration * gaussian_time_cutoff_fwhm
1037 case('gaussianI')
1038 ! take into account that for gaussianI, duration is FWHM of intensity
1039 tt = lf%duration * gaussian_time_cutoff_fwhm * sqrt(2.d0)
1040 case('linear','linear2')
1041 tt = lf%duration * 0.5d0 + lf%rampon
1042 case ('sin2','sin_exp')
1043 tt = lf%duration * 0.5d0
1044 case default
1045 write(0,*) 'ERROR: laser field form unknown, form = ',lf%form
1046 stop 521
1047 end select
1048 end function lf_get_halftotaltime
1049 !---------------------------------------------------------------------------
1050 real(dp) function lf_get_starttime(lf) result(tt)
1051 type(laserfield), intent(in) :: lf
1052 if (lf%form=='readin') then
1053 tt = lf%tt(1)
1054 else
1055 tt = lf%peak_time - lf_get_halftotaltime(lf)
1056 end if
1057 end function lf_get_starttime
1058 !---------------------------------------------------------------------------
1059 real(dp) function lf_get_endtime(lf) result(tt)
1060 type(laserfield), intent(in) :: lf
1061 if (lf%form=='readin') then
1062 tt = lf%tt(size(lf%tt))
1063 else
1064 tt = lf%peak_time + lf_get_halftotaltime(lf)
1065 end if
1066 end function lf_get_endtime
1067 !---------------------------------------------------------------------------
1068 real(dp) function laserfields_starttime() result(tt)
1069 integer :: ii
1070 tt = huge(1.d0)
1071 do ii = 1, n_laserfields
1072 tt = min(tt, lf_get_starttime(all_laserfields(ii)))
1073 end do
1074 end function laserfields_starttime
1075 !---------------------------------------------------------------------------
1076 real(dp) function laserfields_endtime() result(tt)
1077 integer :: ii
1078 tt = -huge(1.d0)
1079 do ii = 1, n_laserfields
1080 tt = max(tt, lf_get_endtime(all_laserfields(ii)))
1081 end do
1082 end function laserfields_endtime
1083 !---------------------------------------------------------------------------
1084 function laserfields_smallest_tx() result(TX)
1085 real(dp) :: tx
1086 integer :: ii
1087 tx = huge(1.d0)
1088 do ii = 1, n_laserfields
1089 if (all_laserfields(ii)%TX < tx) tx = all_laserfields(ii)%TX
1090 end do
1091 end function laserfields_smallest_tx
1092 !---------------------------------------------------------------------------
1093 !> This function gives the maximum timestep that resolves the current oscillation well.
1094 !> the global parameter minimum_steps_per_laser_period determines how large the timestep here is allowed to be.
1095 real(dp) function laserfields_largest_possible_dt(zeit,endzeit,global) result(dt)
1096 real(dp), intent(in) :: zeit
1097 real(dp), intent(in), optional :: endzeit
1098 real(dp) :: tstart, tend, omega, tx
1099 integer :: ii
1100 logical, intent(in), optional :: global
1101
1102 ! if endzeit is specified, that is the time until which we want to propagate at most
1103 if (present(endzeit)) then
1104 if (endzeit <= zeit) then
1105 ! we have already passed endzeit, but still want to do an extra step - shouldn't normally happen!
1106 ! do at least a very small step - the smallest possible that still changes zeit
1107 dt = nearest(zeit,1.d0)-zeit
1108 return
1109 end if
1110 ! normally, have the time until endzeit be the maximum timestep
1111 dt = endzeit-zeit
1112 else
1113 ! otherwise, do steps of at most 100 atomic units
1114 dt = 100.d0
1115 end if
1116
1117 ! if global is requested, we just get the global maximum timestep
1118 if (present(global)) then
1119 if (global) then
1121 return ! exit function
1122 end if
1123 end if
1124
1125 ! otherwise, loop over laser fields and get the maximum timestep allowed at this time (doing at most minimum_steps_per_laser_period steps per period)
1126 do ii = 1, n_laserfields
1127 tstart = lf_get_starttime(all_laserfields(ii))
1129
1130 ! this laser field is only relevant if we are before its endtime
1131 if (zeit < tend) then
1132 if (zeit >= tstart) then
1133 if (all_laserfields(ii)%omega==0) then
1134 ! for fields without oscillation, we want 500 steps for the whole field
1135 dt = min(dt,(all_laserfields(ii)%duration+2*all_laserfields(ii)%rampon)/500)
1136 else
1137 ! if it's currently active, dt has to be at most TX(zeit)/minimum_steps_per_laser_period, where TX depends on zeit for chirped pulses
1138 call lf_get_omega(all_laserfields(ii),zeit,omega)
1139 tx = twopi / omega
1140 dt = min(dt,tx/minimum_steps_per_laser_period)
1141 end if
1142 else if (zeit+dt > tstart) then
1143 ! if we would go beyond the starttime, decrease dt to go only there
1144 dt = tstart - zeit
1145 end if
1146 end if
1147 end do
1148
1150 !---------------------------------------------------------------------------
1151 subroutine write_laserfields(unit,timestep)
1152 use atomic_units
1153 integer, intent(in) :: unit
1154 real(dp), intent(in), optional :: timestep
1155 real(dp) :: tt, endtime
1156 real(dp) :: EL, AL, ZL
1157 real(dp), dimension(n_laserfields) :: env, part
1158
1159 write(unit,'(A)') '# t E(t) A(t) Z(t) I(t) [E_ii(t)] [envelope_ii(t)]'
1160
1162 endtime = laserfields_endtime()
1163 do
1164 el = get_el(tt, env, part)
1165 al = get_al(tt)
1166 zl = get_zl(tt)
1167 write(unit,'(9999(1x,g22.14e3))') tt, el, al, zl, el**2/au_wcm2toel2, part(:), env(:)
1168 if (tt >= endtime) exit
1169
1170 if (present(timestep)) then
1171 tt = tt + timestep
1172 else
1173 tt = tt + laserfields_largest_possible_dt(tt,endtime)
1174 end if
1175 end do
1176 end subroutine write_laserfields
1177 !---------------------------------------------------------------------------
1178 real(dp) function laserfield_teff(lf,n_photon) result(teff)
1179 type(laserfield), intent(in) :: lf
1180 integer, intent(in) :: n_photon
1181 ! returns the "effective duration" of a laser field for n-photon processes
1182 ! the values for T_eff are calculated according to
1183 ! I_0^n * T_eff = \Int_0^T I(t)^n dt = \Int_0^T envelope(t)^(2n) dt
1184 ! calculations done in intensity_integrals.nb
1185 select case (lf%form)
1186 case('gaussianF')
1187 ! result for exp(-t^2/(r*T^2)) = T sqrt(r PI / 2n)
1188 ! for gaussian, r = 1/log(16)
1189 teff = lf%duration * sqrt(pio2/(n_photon*log(16.d0)))
1190 case('gaussianI')
1191 ! for gaussianI, r = 1/log(4)
1192 teff = lf%duration * sqrt(pio2/(n_photon*log(4.d0)))
1193 case('sin2')
1194 teff = lf%duration * gamma(0.5d0+n_photon*2) / (sqrt(pi)*gamma(1.d0+n_photon*2))
1195 case('sin_exp')
1196 teff = lf%duration * gamma(0.5d0+n_photon*lf%form_exponent) / (sqrt(pi)*gamma(1.d0+n_photon*lf%form_exponent))
1197 case('linear')
1198 teff = lf%duration + 2*lf%rampon / (1+2.d0*n_photon)
1199 case('linear2')
1200 ! flat top for lf%duration with a sin2 pulse of duration 2*lf%rampon as rampon/off
1201 teff = lf%duration + 2*lf%rampon * gamma(0.5d0+n_photon*2) / (sqrt(pi)*gamma(1.d0+n_photon*2))
1202 case default
1203 write(0,*) 'ERROR: effective duration not implemented for laser field form ', lf%form
1204 stop
1205 end select
1206 end function laserfield_teff
1207 !---------------------------------------------------------------------------
1208 real(dp) function laserfield_int(lf,n_photon)
1209 use atomic_units
1210 type(laserfield), intent(in) :: lf
1211 integer, intent(in) :: n_photon
1212 laserfield_int = laserfield_teff(lf,n_photon) * (lf%intensity_Wcm2 * au_wcm2)**n_photon
1213 end function laserfield_int
1214 !---------------------------------------------------------------------------
1215 real(dp) function tdcs_factor(lf,n_photon)
1216 use atomic_units
1217 real(dp), parameter :: csunit(2) = (/ 1.d24*au_ev/((au_cm)**2), 1.d55*au_ev/((au_cm)**4*au_as*1.d18) /)
1218 type(laserfield), intent(in) :: lf
1219 integer, intent(in) :: n_photon
1220 if (n_photon < 1 .or. n_photon > 2) stop 'ERROR: Only n_photon = {1,2} allowed for tdcs_factor in laserfields module'
1221 tdcs_factor = csunit(n_photon) * lf%omega**n_photon / laserfield_int(lf,n_photon)
1222 end function tdcs_factor
1223 !-------------------------------------------------------------------
1224 real(dp) function cs_factor(lf,n_photon)
1225 use atomic_units
1226 real(dp), parameter :: csunit(2) = (/ 1.d21/(au_cm)**2, 1.d52/((au_cm)**4*au_as*1.d18) /)
1227 type(laserfield), intent(in) :: lf
1228 integer, intent(in) :: n_photon
1229 if (n_photon < 1 .or. n_photon > 2) stop 'ERROR: Only n_photon = {1,2} allowed for CS_factor in laserfields module'
1230 cs_factor = csunit(n_photon) * lf%omega**n_photon / laserfield_int(lf,n_photon)
1231 end function cs_factor
1232 !-------------------------------------------------------------------------
1233 logical function laserfields_can_get_fourier() result(yes_we_can)
1234 integer :: i_field
1235 yes_we_can = .true.
1236 do i_field = 1, n_laserfields
1237 yes_we_can = yes_we_can .and. lf_can_get_fourier(all_laserfields(i_field))
1238 end do
1239 end function laserfields_can_get_fourier
1240 !-------------------------------------------------------------------------
1241 logical function lf_can_get_fourier(lf) result(yes_we_can)
1242 type(laserfield), intent(in) :: lf
1243 yes_we_can = .true.
1244 select case (lf%form)
1245 case('gaussianF','gaussianI','sin2')
1246 continue
1247 case('sin_exp','readin')
1248 write(0,'(9a)') 'WARNING: can not get analytical fourier transform for ', trim(lf%form), ' fields!'
1249 yes_we_can = .false.
1250 case('linear','linear2')
1251 if (lf%linear_chirp_rate_w0as /= 0.d0) then
1252 write(0,'(9a)') 'WARNING: can not get analytical fourier transform for chirped ', trim(lf%form), ' fields!'
1253 yes_we_can = .false.
1254 end if
1255 end select
1256 end function lf_can_get_fourier
1257 !-------------------------------------------------------------------------
1258 complex(dpc) function lf_get_el_fourier_transform(lf,omega) result(ELFT)
1259 ! analytically determine the fourier transform of the defined laser fields
1260 ! determined as 1/sqrt(2pi) Int exp(-i*omega*t) E(t) dt
1261 use atomic_units
1262 type(laserfield), intent(in) :: lf
1263 real(dp), intent(in) :: omega
1264
1265 if (.not.lf_can_get_fourier(lf)) then
1266 write(0,'(A,I2,A)') 'ERROR! can not get analytic fourier transform for this laser field! stopping!'
1267 stop 1103
1268 end if
1269
1270 if (lf%omega==0) then ! No oscillation enclosed by envelope
1271 elft = lf_envelope_fourier(lf,omega)
1272 else
1273 ! with tp = t-tpeak, the whole pulse is
1274 ! f(t) = env(t) sin (phi0 + w0*tp + chirp*tp**2)
1275 ! = (env(t) exp(IU*(phi0 + w0*tp + chirp*tp**2)) - c.c. ) / (2*IU)
1276 ! for the fourier transform, we include the chirp term exp(i chirp tp**2) in the envelope.
1277 ! this part is transformed in lf_envelope_fourier.
1278 ! exp(IU*phi0) is just a constant prefactor, and the linear phase w0*tp just gives a shift in frequency,
1279 ! F[f(t) exp(IU w0 t)](w) = F[f(t)](w-w0)
1280 ! complex conjugation of the transformed function gives complex conjugation + reversal of the argument in the transform, so
1281 ! F[conjg(f(t) exp(IU w0 t))](w) = conjg(F[f(t) exp(IU w0 t)](-w)) = conjg(F[f(t)](-w-w0))
1282
1283 elft = ( lf_envelope_fourier(lf, omega - lf%omega) * exp( iu*pi*lf%phase_pi) &
1284 & - conjg(lf_envelope_fourier(lf, -omega - lf%omega)) * exp(-iu*pi*lf%phase_pi) ) / (2*iu)
1285 end if
1286
1287 ! the fourier transform of the part was determined as if it was centered around t=0
1288 ! shift in time now -- just adds a phase exp(-IU*omega*peak_time), as F[f(t-a)] = exp(-IU*omega*a) F[f(t)]
1289 elft = elft * exp(-iu*omega*lf%peak_time)
1290
1291 if (lf%is_vecpot) then
1292 ! if this laser field was defined as a vector potential, we need to multiply with -IU*omega to get the fourier transform of the electric field, E=-dA/dt
1293 ! F[-dA/dt] = -iw F[A]
1294 elft = -iu * omega * elft
1295 ! in addition, we need to take into account that A0 = E0 / lf%omega if we have an oscillation
1296 if (lf%omega/=0) elft = elft / lf%omega
1297 end if
1298
1299 end function lf_get_el_fourier_transform
1300 !-------------------------------------------------------------------------
1301 character(4000) function lf_get_el_fourier_transform_string(lf) result(Ff)
1302 ! analytically determine the fourier transform of the defined laser fields
1303 ! determined as 1/sqrt(2pi) Int exp(-i*omega*t) E(t) dt
1304 use atomic_units
1306 type(laserfield), intent(in) :: lf
1307
1308 if (.not.lf_can_get_fourier(lf)) then
1309 write(0,'(A,I2,A)') 'ERROR! can not get analytic fourier transform for this laser field! stopping!'
1310 stop 1103
1311 end if
1312
1313 if (lf%omega==0) then ! No oscillation enclosed by envelope
1314 ff = trim(lf_envelope_fourier_string(lf,'w'))
1315 else
1316 ! with tp = t-tpeak, the whole pulse is
1317 ! f(t) = env(t) sin (phi0 + w0*tp + chirp*tp**2)
1318 ! = (env(t) exp(IU*(phi0 + w0*tp + chirp*tp**2)) - c.c. ) / (2*IU)
1319 ! for the fourier transform, we include the chirp term exp(i chirp tp**2) in the envelope.
1320 ! this part is transformed in lf_envelope_fourier.
1321 ! exp(IU*phi0) is just a constant prefactor, and the linear phase w0*tp just gives a shift in frequency,
1322 ! F[f(t) exp(IU w0 t)](w) = F[f(t)](w-w0)
1323 ! complex conjugation of the transformed function gives complex conjugation + reversal of the argument in the transform, so
1324 ! F[conjg(f(t) exp(IU w0 t))](w) = conjg(F[f(t) exp(IU w0 t)](-w)) = conjg(F[f(t)](-w-w0))
1325 ff = '('//trim(lf_envelope_fourier_string(lf, ' w - '//gnuplotstring(lf%omega))) &
1326 & //' * '//gnuplotstring(exp( iu*pi*lf%phase_pi))// &
1327 & '- conjg('//trim(lf_envelope_fourier_string(lf, '-w - '//gnuplotstring(lf%omega))) &
1328 & //') * '//gnuplotstring(exp(-iu*pi*lf%phase_pi))//') / {0,2}'
1329 end if
1330
1331 ! the fourier transform of the part was determined as if it was centered around t=0
1332 ! shift in time now -- just adds a phase exp(-IU*omega*peak_time), as F[f(t-a)] = exp(-IU*omega*a) F[f(t)]
1333 ff = trim(ff) // ' * exp('//gnuplotstring(-iu*lf%peak_time)//'*w)'
1334
1335 if (lf%is_vecpot) then
1336 ! if this laser field was defined as a vector potential, we need to multiply with -IU*omega to get the fourier transform of the electric field, E=-dA/dt
1337 ! F[-dA/dt] = -iw F[A]
1338 ! in addition, we need to take into account that A0 = E0 / lf%omega
1339 ff = '('//trim(ff)//' * '//gnuplotstring(-iu/lf%omega)//'*w)'
1340 end if
1341 end function lf_get_el_fourier_transform_string
1342 !-------------------------------------------------------------------------
1343 complex(dpc) function lf_get_al_fourier_transform(lf,omega) result(ALFT)
1344 ! analytically determine the fourier transform of the defined laser fields
1345 ! determined as 1/sqrt(2pi) Int exp(-i*w*t) A(t) dt
1346 ! use connection with electric field:
1347 ! A(t) = 1/sqrt(2pi) Int exp(i w t) A(w) dw
1348 ! -dA/dt = 1/sqrt(2pi) Int exp(i w t) (-iw) A(w) dw = E(t) = 1/sqrt(2pi) Int exp(i w t) E(omega) dw
1349 ! --> E(omega) = (-iw) A(omega)
1350 type(laserfield), intent(in) :: lf
1351 real(dp), intent(in) :: omega
1352 ! is undefined if called with omega=0.d0, so set to zero for that value
1353 alft = 0
1354 if (omega /= 0.d0) alft = get_el_fourier_transform(lf,omega) / (-iu*omega)
1355 end function lf_get_al_fourier_transform
1356 !-------------------------------------------------------------------------
1357 complex(dpc) function laserfields_get_el_fourier_transform(omega) result(ELFT)
1358 real(dp), intent(in) :: omega
1359 integer :: i_field
1360 elft = 0
1361 do i_field = 1, n_laserfields
1362 elft = elft + get_el_fourier_transform(all_laserfields(i_field),omega)
1363 end do
1364 end function laserfields_get_el_fourier_transform
1365 !-------------------------------------------------------------------------
1366 character(4000) function laserfields_get_el_fourier_transform_string() result(Ff)
1367 integer :: i_field
1369 do i_field = 2, n_laserfields
1370 ff = trim(ff)//' + '//get_el_fourier_transform_string(all_laserfields(i_field))
1371 end do
1372 end function laserfields_get_el_fourier_transform_string
1373 !-------------------------------------------------------------------------
1374 complex(dpc) function laserfields_get_al_fourier_transform(omega) result(ALFT)
1375 real(dp), intent(in) :: omega
1376 integer :: i_field
1377 alft = 0
1378 do i_field = 1, n_laserfields
1379 alft = alft + get_al_fourier_transform(all_laserfields(i_field),omega)
1380 end do
1381 end function laserfields_get_al_fourier_transform
1382 !-------------------------------------------------------------------------
1383end module laserfields_module
convert real or complex numbers to strings that can be used in gnuplot
1-dimensional polynomial interpolation
Return the fourier transform . if called with a type(laserfield) argument, gets for just that one fi...
Return the positive-frequency part of the vector potential A^(+)(t). if called with a type(laserfield...
Return the vector potential A(t). if called with a type(laserfield) argument, gets A(t) for just that...
Return the fourier transform E(ω) as a string that can be used as a function in gnuplot....
Return the fourier transform . if called with a type(laserfield) argument, gets for just that one fi...
Return the positive-frequency part of the electric field E^(+)(t). if called with a type(laserfield) ...
Return the electric field E(t). if called with a type(laserfield) argument, gets E(t) for just that o...
Return the free-space displacement Z(t) of an electron. if called with a type(laserfield) argument,...
Make a new type(laserfield), either from parameters or reading from a datafile.
conversion factors for various units to/from atomic units based on the 2012-10-28 CODATA values from ...
real(dp), parameter au_wcm2toel2
EF [a.u.] = sqrt(I [W/cm2] * au_Wcm2toEL2),.
real(dp), parameter au_wcm2
I [a.u.] = I [W/cm2] * au_Wcm2.
real(dp), parameter au_nm
x [a.u.] = x [nm] * au_nm
real(dp), parameter au_c
speed of light in a.u. == 1/alpha
real(dp), parameter au_ev
E [a.u.] = E [eV] * au_eV (in Hartree atomic units).
real(dp), parameter au_cm
x [a.u.] = x [cm] * au_cm
real(dp), parameter au_as
t [a.u.] = t [attoseconds] * au_as
integer function get_unused_unit()
real(dp) function lf_get_endtime(lf)
subroutine write_laserfields(unit, timestep)
real(dp) function laserfield_int(lf, n_photon)
integer n_laserfields
Number of laserfields in the global array all_laserfields.
complex(dpc) function expiatbt2_intt(a, b, t)
subroutine add_laserfield(lf)
add a type(laserfield) to the global list all_laserfields
real(dp) function cs_factor(lf, n_photon)
real(dp) function laserfields_endtime()
subroutine read_laserfield_from_file(lf)
integer, parameter minimum_steps_per_laser_period
character(1000) function lf_envelope_fourier_string(lf, omegastr)
real(dp) function lf_get_halftotaltime(lf)
logical function lf_can_get_fourier(lf)
logical function laserfields_can_get_fourier()
type(laserfield), dimension(100) all_laserfields
Global array saving the laserfields read from parameter files and added with add_laserfield.
subroutine lf_get_omega(lf, zeit, omega, env)
real(dp) function laserfields_smallest_tx()
subroutine lf_setup_aa_interpolation(lf)
subroutine laserfield_set_dependent(lf)
real(dp) function lf_get_starttime(lf)
subroutine lf_setup_zz_interpolation(lf)
real(dp) function laserfield_teff(lf, n_photon)
subroutine laserfield_numerical_integration_a_from_e(lf)
complex(dpc) function lf_envelope_fourier(lf, omega)
real(dp) function laserfields_largest_possible_dt(zeit, endzeit, global)
This function gives the maximum timestep that resolves the current oscillation well....
subroutine laserfield_numerical_derivation_e_from_a(lf)
real(dp) function tdcs_factor(lf, n_photon)
real(dp) function laserfields_starttime()
real(dp), parameter gaussian_time_cutoff_fwhm
subroutine lf_get_envelope(lf, zeit, env, envpr)
subroutine laserfield_numerical_integration_z_from_a(lf)
integer, parameter dp
Definition nrtype.f90:6
Datatype describing a single laserfield, should usually be created through make_laserfield routine.