From 3a0e45e95b9744c14790791f31c4a3d06c5ece2c Mon Sep 17 00:00:00 2001 From: kamischi <karl-michael.schindler@web.de> Date: Fri, 13 Jan 2023 17:52:54 +0100 Subject: [PATCH] commented source code added. --- .../boson_all.f90.fcat-analysis.txt | 972 ++++++++++++ .../eels_all.f90.fcat-analysis.txt | 1353 +++++++++++++++++ 2 files changed, 2325 insertions(+) create mode 100644 source/f90/fcat-analysis/boson_all.f90.fcat-analysis.txt create mode 100644 source/f90/fcat-analysis/eels_all.f90.fcat-analysis.txt diff --git a/source/f90/fcat-analysis/boson_all.f90.fcat-analysis.txt b/source/f90/fcat-analysis/boson_all.f90.fcat-analysis.txt new file mode 100644 index 0000000..8d97d00 --- /dev/null +++ b/source/f90/fcat-analysis/boson_all.f90.fcat-analysis.txt @@ -0,0 +1,972 @@ +program boson + +! ******************************************************************* +! * * +! * perform the quantum-mechanical complement to the classical step * +! * of the dielectric theory of eels in specular geometry using a * +! * suitable thermodynamical average of the quantized surface * +! * harmonic oscillators * +! * * +! ******************************************************************* + + implicit none + + integer, parameter :: mmax=14, nmax=2**mmax + double precision :: asym, emax, emin, gauss, t, width, wmin, wmax, y + double precision :: p2(nmax) + integer :: i, np, ioStatus + character (len = 72) :: comment(2) + double precision, allocatable :: xout(:), yout(:) + integer :: nout + +! *** read input parameters + +1 call change_working_dir() +1 open(unit = 13, file = 'bosin') +! target temperature (Kelvin) +1 read(13, *) t +! width of the instrumental response (cm**-1) +1 read(13, *) width +! fraction of gaussian for the instrumental response +1 read(13, *) gauss +! asymmetry of the instrumental response +1 read(13, *) asym +! lower and upper energy losses for this computation (cm**-1) +1 read(13, *) emin +1 read(13, *) emax +1 close(unit=13) + +1 write(*,*) 'program boson (September 2020)' +1 write(*,'(a, f6.1, a, f7.2, a)') ' t =', t, ' K, width =', width, ' cm**-1' +1 write(*,'(a, f5.2, a, f5.2)') ' gauss =', gauss, ', asym =', asym +1 write(*,'(a, g11.4, a, g11.4, a)') ' energy losses from', emin, ' to', emax, ' cm**-1' + +! *** read the table of values of the classical loss spectrum + +1 open(unit = 12, file = 'eelsou') +1 read(12, '(a48)') comment(1) +1 read(12, '(a72)') comment(2) +1 np = 0 +1 do +327 read(12, *, IOSTAT = ioStatus) wmax, y +327 if (ioStatus /= 0) exit +326 if (wmax < 0.0d0) cycle +326 np = np + 1 +326 p2(np) = y +326 if (np == 1) wmin = wmax +326 if (np < nmax) cycle +*> enddo +1 close(unit = 12) + +1 if (np <= 0) stop '*** no input values for pcl ***' + +1 write(*,*) comment(2) +1 write(*,'(a, i6, a, g15.7, a, g15.7)') ' read', np, ' values of pcl from', wmin, ' to', wmax + +! length calculation for xout, yout. +! +1 nout = 2**14 +1 allocate (xout(nout)) +1 allocate (yout(nout)) + +1 call doboson(t, width, gauss, asym, emin, emax, wmin, wmax, np, p2, xout, yout, nout) + +1 open(unit = 14, file = 'bosou') +1 write(14, '(a, a, f6.1, a, f5.2)') comment(1), 'T =', t, ' GAUSS =', gauss +1 write(14, *) comment(2) +1 do i = 1, nout +851 write(14, '(2e15.7)') xout(i), yout(i) +851 end do +1 close(unit = 14) +1 write(*,*) nout, ' values written on disk' + +1 deallocate (xout, yout) +1 stop +end program boson +subroutine change_working_dir() + +! This routine gets the first argument of the commandline and takes it +! as the path to change the working directory +! used intrinsic routines: +! iarg returns the number of commandline arguments without the program cname. +! chdir changes the directory and returns 0 on success. +! trim removes blanks from strings. + + character (len = 256) :: argument + integer :: status + +1 if (iargc() == 1) then +*> call getarg(1, argument) +*> status = chdir(trim(argument)) +*> if (status /= 0) then +*> write (*,*) '*** change directory failed ***' +*> write (*,*) 'directory tried: ', trim(argument) +*> write (*,*) 'error code (see: man chdir): ', status +*> write (*,*) 'continuing in the start directory' +*> end if +*> end if + +1 return +end subroutine change_working_dir +double precision function respon(w, width) + +!******************************************************************* +! * +! instrumental response of the spectrometer for the frequency w * +! width is the full width at half maximum of the response function * +! * +!******************************************************************* + + implicit none + double precision, intent(in) :: w, width + + double precision :: u + +*> u = 1.25d0 * w / width +*> if (u <= -1.0d0 .or. u >= 2.0d0) then +*> respon = 0.0d0 +*> elseif (u > 1.0d0) then +*> respon = 4.0d0 + 2 * dsqrt((u - 1.0d0)**3) - 3 * u +*> elseif (u > 0.0d0) then +*> respon = 2.0d0 - 4 * dsqrt(u**3) + 3 * u +*> else +*> respon = 2 * dsqrt((u + 1.0d0)**3) +*> endif +*> return +end function respon +module sicot_mod +contains +subroutine sicot(f, m, h, x0) + +! ******************************************************************* +! * * +! * integral transform g(y, x0) of a real function f(x) defined by * +! * * +! * g(x0, y) = integral of f(x)/tanh(x/x0)*(1-cos(x*y)) dx * +! * * +! * f(x) is tabulated on the mesh of points xj = (j-1/2)*h , * +! * j = 1, 2, ..., n , with n = 2**m * +! * g(x0, y) is computed on the mesh of points yk = k*2pi/(n*h) , * +! * k = 0, 1, 2, ..., n-1 * +! * * +! * input ... * +! * f(j) contains the value of f(xj) , j = 1, 2, ..., n * +! * m is such that n = 2**iabs(m) * +! * h is the step size (must be positive) * +! * * +! * output ... * +! * f(k+1) contains g(x0, yk), k = 0, 1, ..., n-1 * +! * * +! * computing remarks ... * +! * f is a real array with dimension n or more * +! * it is supposed that f(x) is zero for x > n*h * +! * external reference : sintr (sine transform of a real function). * +! * * +! ******************************************************************* + + use sintr_mod + + implicit none + + double precision, intent(in out) :: f(*) + integer, intent(in) :: m + double precision, intent(in) :: h + double precision, intent(in) :: x0 + + double precision :: a, b, c, d, e, s, sa + integer :: i, j, msign, n + + logical :: debug + +1 debug = .false. +1 if (m == 0) then +*> f(1) = 0.0d0 +*> return +*> endif + +1 if (h <= 0.0d0) then +*> if (debug) write(*,*) ' *** incorrect step size in <sicot>, h =', h, ' ***' +*> stop +*> endif + +1 if (x0 < 0.0d0) then +*> if (debug) write(*,*) ' *** incorrect input in <sicot>, x0 =', x0, ' ***' +*> stop +*> endif + +1 n = 2**iabs(m) + +! *** evaluate the integral from xj to infinity of f(x)/tanh(x/x0) dx +! and store the result in f(j) + +1 c = 0.0d0 +1 if (x0 > h / 16) then +1 c = dexp(-h / x0) +1 endif +1 s = 1.0d0 - c +1 e = c**2 +1 a = 0.25d0 * h +1 b = 0.25d0 * x0 +1 do i = 1, n +4096 if (i < n) then +4095 f(i) = f(i) + f(i+1) +4095 endif +4096 d = a +4096 if (s /= 1.0d0) then +3902 sa = s +3902 c = c * e +3902 s = 1.0d0 - c +3902 d = d + b * dlog(s / sa) +3902 endif +4096 f(i) = f(i) * d +4096 enddo + +1 j = n +1 do i = 2, n +4095 j = j - 1 +4095 f(j) = f(j) + f(j + 1) +4095 enddo +! alternative, but not yet tested: +! do j = n - 1, 1, -1 +! f(j) = f(j) + f(j + 1) +! enddo +1 msign = -iabs(m) +1 call sintr(f, msign, h) +1 return +end subroutine sicot +end module sicot_mod +module sintr_mod +contains +subroutine sintr(f, msign, h) + +! ******************************************************************* +! * * +! * integral sine transform of a real function f(x) * +! * * +! * g(y) = integral from zero to infinity of f(x)*sin(x*y) dx * +! * if msign >= 0 or * +! * g(y) = y * integral from zero to infinity of f(x)*sin(x*y) dx * +! * if msign < 0 * +! * * +! * f(x) is tabulated on the mesh of points xj = (j-1/2)*h , * +! * j = 1, 2, ..., n , with n = 2**iabs(msig) * +! * g(y) is computed on the mesh of points yk = k*2pi/(n*h) , * +! * k = 0, 1, 2, ..., n-1 * +! * * +! * input ... * +! * f(j) contains the value of f(xj) , j = 1, 2, ..., n * +! * msign is such that n = 2**iabs(msign) * +! * h is the step size (must be positive) * +! * * +! * output ... * +! * f(k+1) contains g(yk), k = 0, 1, ..., n-1 * +! * * +! * computing remarks ... * +! * f is a real array with dimension n or more * +! * it is supposed that f(x) is zero for x > n*h * +! * * +! ******************************************************************* + + implicit none + + double precision, intent(in out) :: f(*) + integer, intent(in) :: msign + double precision, intent(in) :: h + + double precision :: a, c, ca, d, e, fnp1, s, sa, ti, ti1, ti2, tr, tr1, tr2 + double precision :: ui, ur, wi, wr + integer :: i, i2, ip2, j, j2, k, l, le, le1, m2, n, n2, nm1, nv2 + + logical :: debug + +2 debug = .false. +2 if (h <= 0.0d0) then +*> if (debug) write(*,*) ' *** incorrect step size in <sintr>, h: ', h, ' ***' +*> stop +*> endif + +2 if (msign == 0) then +*> f(1) = 0.0d0 +*> return +*> endif + +! *** for j and k = 0, 1, 2 ... n/2-1, compute +! s1 = sum ( f(2*j+1)*cos(4*pi*k*j/n) - f(2*j+2)*sin(4*pi*k*j/n) ) +! s2 = sum ( f(2*j+1)*sin(4*pi*k*j/n) + f(2*j+2)*cos(4*pi*k*j/n) ) +! store s1 in f(2*k+1) and s2 in f(2*k+2) +! (adapted from cfft routine, cern library member d704) + +2 m2 = iabs(msign) - 1 +2 n = 2**m2 +2 if (n /= 1) then +2 nv2 = n / 2 +2 nm1 = n - 1 +2 j = 1 +2 do i = 1, nm1 +4094 if (i < j) then +1984 i2 = i + i +1984 j2 = j + j +1984 ti = f(j2) +1984 f(j2) = f(i2) +1984 f(i2) = ti +1984 i2 = i2 - 1 +1984 j2 = j2 - 1 +1984 tr = f(j2) +1984 f(j2) = f(i2) +1984 f(i2) = tr +1984 endif +4094 k = nv2 +4094 do while (j > k) +4072 j = j - k +4072 k = k / 2 +4072 enddo +4094 j = j + k +4094 enddo +2 do i = 1, n, 2 +2048 i2 = i + i +2048 ti = f(i2 + 2) +2048 f(i2 + 2) = f(i2) - ti +2048 f(i2) = f(i2) + ti +2048 i2 = i2 - 1 +2048 tr = f(i2 + 2) +2048 f(i2 + 2) = f(i2) - tr +2048 f(i2) = f(i2) + tr +2048 enddo +2 if (m2 /= 1) then +2 c = 0.0d0 +2 s = 1.0d0 +2 le = 2 +2 do l = 2, m2 +20 wr = c +20 wi = s +20 ur = wr +20 ui = wi +20 c = dsqrt(c * 0.5d0 + 0.5d0 ) +20 s = s / (c + c) +20 le1 = le +20 le = le1 + le1 +20 do i = 1, n, le +2046 i2 = i + i +2046 ip2 = i2 + le +2046 ti = f(ip2) +2046 f(ip2) = f(i2) - ti +2046 f(i2) = f(i2) + ti +2046 i2 = i2 - 1 +2046 ip2 = ip2 - 1 +2046 tr = f(ip2) +2046 f(ip2) = f(i2) - tr +2046 f(i2) = f(i2) + tr +2046 enddo +20 do j = 2, le1 +4072 do i = j, n, le +18434 i2 = i + i +18434 ip2 = i2 + le +18434 tr = f(ip2 - 1) * ur - f(ip2) * ui +18434 ti = f(ip2) * ur + f(ip2 - 1) * ui +18434 f(ip2) = f(i2) - ti +18434 f(i2) = f(i2) + ti +18434 i2 = i2 - 1 +18434 ip2 = ip2 - 1 +18434 f(ip2) = f(i2) - tr +18434 f(i2) = f(i2) + tr +18434 enddo +4072 tr = ur * wr - ui * wi +4072 ui = ui * wr + ur * wi +4072 ur = tr +4072 enddo +20 enddo +2 endif +2 endif + +! *** for j and k = 0, 1 ... n-1, transform the array f so obtained into +! sum f(j+1)*cos(2*pi*k*j/n) and sum f(j+1)*sin(2*pi*k*j/n) +! and multiply the results by (1 - cos(2*pi*k/n)) and sin(2*pi*k/n) + +2 fnp1 = 4 * (f(1) - f(2)) +2 a = 3.141592653589793238d0 / n +2 n2 = n + 1 +2 n = 2 * n +2 if (n2 /= 2) then +2 c = 1.0d0 +2 s = 0.0d0 +2 ca = dcos(a) +2 sa = dsin(a) +2 k = n + 1 +2 do j = 3, n2, 2 +2048 k = k - 2 +2048 d = c +2048 c = d * ca - s * sa +2048 s = d * sa + s * ca +2048 tr1 = f(j) + f(k) +2048 ti1 = f(j + 1) - f(k + 1) +2048 d = f(j) - f(k) +2048 e = f(j + 1) + f(k + 1) +2048 tr2 = d * s + e * c +2048 ti2 = e * s - d * c +2048 f(j) = (1.0d0 - c) * (tr1 + tr2) +2048 f(j + 1) = s * (ti1 + ti2) +2048 f(k) = (1.0d0 + c) * (tr1 - tr2) +2048 f(k + 1) = s * (ti2 - ti1) +2048 enddo +2 n2 = n2 - 1 +2 do j = 2, n2 +4094 j2 = j + j +4094 f(j) = f(j2 - 1) + f(j2) +4094 enddo +2 do j = 2, n2 +4094 f(n + 2 - j) = f(j) +4094 enddo +2 n2 = n2 + 1 +2 endif +2 f(n2) = fnp1 +2 if (msign >= 0) then + +! *** normalization + +1 c = 0.0d0 +1 a = (a + a) / h +1 do j = 2, n +4095 c = c + a +4095 f(j) = f(j) / c +4095 enddo +1 endif +2 f(1) = 0.0d0 +2 return +end subroutine sintr +end module sintr_mod +module rcffi_mod +contains +subroutine rcffi(ar, ai, msign, h) + +! ******************************************************************* +! * * +! * using a radix-two fast-fourier-transform technique, rcffi * +! * computes the fourier integral transform of a real function * +! * f(x) or the inverse fourier transform of a complex function * +! * such that g(-y) = conj(g(y)). * +! * (adapted from cfft routine, cern library member d704) * +! * * +! * g(y) = integral f(x) * cexp(-i * x * y) dx (msign < 0) * +! * * +! * f(x) = 1 / (2 * pi) integral g(y) * cexp(+i * y * x) dy (msign > 0) * +! * * +! * f(x) is tabulated on the meshes of points defined by * +! * xj = j * hx and -xj = -j * hx, j = 0, +1, ..., n-2, n-1 * +! * ar(j+1) contains f(+xj) and ai(j+1) contains f(-xj) * +! * (input when msign < 0 , output when msign >0) * +! * ar(1) may be different from ai(1) * +! * * +! * g(y) is tabulated on the mesh of points defined by * +! * yk = k * hy , k = 0, 1, ..., n - 2, n - 1 * +! * ar(j+1) contains real(g(yk)) and ai(j+1) contains aimag(g(yk)) * +! * (output when msign > 0 , input when msign < 0) * +! * remark : g(-yk) = conj(g(+yk)) * +! * * +! * n = 2**iabs(msign) (msign is an input) * +! * * +! * the step sizes satisfy * +! * hy = (2 * pi) / (n * hx) or hx = (2 * pi) / (n * hy) * +! * h is an input (h = hx if msign < 0 , h = hy if msign > 0) * +! * h must be positive * +! * * +! * ar and ai are two real arrays with dimension n (input and * +! * output) * +! * * +! ******************************************************************* + + implicit none + + double precision, intent(in out) :: ar(*) + double precision, intent(in out) :: ai(*) + integer, intent(in) :: msign + double precision, intent(in) :: h + + double precision :: a, as, c, s, t, ti, tr, ui, ur, wi, wr + integer :: i, ip, j, k, l, le, le1, m, n, nm1, nv2 + logical :: debug + +1 debug = .false. +1 as = 0.0d0 +1 if (msign == 0) then +*> return +*> endif + +1 if (h <= 0.0d0) then +*> if (debug) write(*,*) ' *** negative step size in <rcffi>, h = ', h, ' *** ' +*> stop +*> endif + +! *** initialization + +1 m = iabs(msign) +1 n = 2**m +1 if (msign > 0) then +1 ar(1) = 0.5d0 * ar(1) +*> else +*> as = ar(1) - ai(1) +*> ar(1) = 0.5d0 * (ar(1) + ai(1)) +*> do i = 2, n +*> ar(i) = ar(i) + ai(n - i + 2) +*> enddo +*> do i = 1, n +*> ai(i) = 0.0d0 +*> enddo +*> endif +! *** discrete fast-fourier transform +1 nv2 = n / 2 +1 nm1 = n - 1 +1 j = 1 +1 do i = 1, nm1 +4095 if (i < j) then +2016 tr = ar(j) +2016 ar(j) = ar(i) +2016 ar(i) = tr +2016 ti = ai(j) +2016 ai(j) = ai(i) +2016 ai(i) = ti +2016 endif +4095 k = nv2 +4095 do while (j > k) +4083 j = j - k +4083 k = k / 2 +4083 enddo +4095 j = j + k +4095 enddo +1 do i = 1, n, 2 +2048 tr = ar(i + 1) +2048 ar(i + 1) = ar(i) - tr +2048 ar(i) = ar(i) + tr +2048 ti = ai(i + 1) +2048 ai(i + 1) = ai(i) - ti +2048 ai(i) = ai(i) + ti +2048 enddo +1 if (m == 1) return +1 c = 0.0d0 +1 s = dble(isign(1, msign)) +1 le = 2 +1 do l = 2, m +11 wr = c +11 ur = wr +11 wi = s +11 ui = wi +11 c = dsqrt(c * 0.5d0 + 0.5d0) +11 s = wi / (c + c) +11 le1 = le +11 le = le1 + le1 +11 do i = 1, n, le +2047 ip = i + le1 +2047 tr = ar(ip) +2047 ar(ip) = ar(i) - tr +2047 ar(i) = ar(i) + tr +2047 ti = ai(ip) +2047 ai(ip) = ai(i) - ti +2047 ai(i) = ai(i) + ti +2047 enddo +11 do j = 2, le1 +4083 do i = j, n, le +20481 ip = i + le1 +20481 tr = ar(ip) * ur - ai(ip) * ui +20481 ti = ar(ip) * ui + ai(ip) * ur +20481 ar(ip) = ar(i) - tr +20481 ar(i) = ar(i) + tr +20481 ai(ip) = ai(i) - ti +20481 ai(i) = ai(i) + ti +20481 enddo +4083 tr = ur +4083 ur = tr * wr - ui * wi +4083 ui = tr * wi + ui * wr +4083 enddo +11 enddo + +! *** correction of the discrete fft, using a trapezoidal approximation +! *** for the variations of the input function + +1 c = h +1 if (msign >= 0) then +1 c = c / 3.141592653589793238d0 +1 ai(1) = ar(1) +1 do i = 2, n +4095 ai(i) = ar(n - i + 2) +4095 enddo +1 endif +1 ar(1) = c * ar(1) +1 ai(1) = c * ai(1) +1 a = 3.141592653589793238d0 / n +1 wr = dcos(a) +1 wi = dsin(a) +1 t = dsqrt(c) +1 a = a / t +1 c = 0.0d0 +1 ur = 1.0d0 +1 ui = 0.0d0 +1 do i = 2, n +4095 c = c + a +4095 tr = ur +4095 ur = wr * tr - wi * ui +4095 ui = wi * tr + wr * ui +4095 ti = ui / c +4095 tr = ti**2 +4095 ar(i) = ar(i) * tr +4095 ai(i) = ai(i) * tr +4095 if (msign <= 0) then +*> if (as /= 0.0d0) then +*> ai(i) = ai(i) - as * (t - ur * ti) / (2 * c) +*> endif +*> endif +4095 enddo +1 return +end subroutine rcffi +end module rcffi_mod +subroutine doboson(t, width, gauss, asym, emin, emax, wmin, wmax, np, p, xout, yout, nout) + +! ******************************************************************* +! * * +! * perform the quantum-mechanical complement to the classical step * +! * of the dielectric theory of eels in specular geometry using a * +! * suitable thermodynamical average of the quantized surface * +! * harmonic oscillators * +! * * +! * t: Target temperature * +! * width: Width of instrumental response (cm**-1) * +! * gauss: Fraction of gaussian for the instrumental response * +! * asym: Asymmetry of the instrumental response * +! * emin: Lower loss energy for this computation (cm**-1) * +! * emax: Upper loss energy for this computation (cm**-1) * +! * wmin: Lower loss energy of the eels computation (cm**-1) * +! * wmax: Upper loss energy of the eels computation (cm**-1) * +! * np: Number of points of the eels computation * +! * p: Intensities of the eels computation * +! * xout: Energies of this computation * +! * yout: Intensities of this computation * +! * nout: Number of points of this computation * +! ******************************************************************* + + use rcffi_mod + use sicot_mod + use sintr_mod + + implicit none + + double precision, intent(in) :: t, width, gauss, asym, emin, emax, wmin + double precision, intent(in out) :: wmax + integer, intent(in) :: np + double precision, intent(in) :: p(np) + double precision, intent(in out) :: xout(nout), yout(nout) + integer, intent(in out) :: nout + + integer, parameter :: mmax = 14, nmax = 2**mmax + double precision :: a, a1, a2, alfa, anorm, b, cp2, dwn, fac, fi + double precision :: fm, fm0, fm1, fp1, fmpic, fp, fp0, fppic, fr, g1, g2 + double precision :: h, pi, sigma, sp2, test, u + double precision :: wmpic, wppic, wn, x, x1, x2, x3 + double precision :: o1, o2, respon + + external o1, o2 + + integer :: i, imax, imin, istep, j, jmin, jmax, m, n + logical :: picm, picp + double precision, allocatable :: p1(:), p2(:) + double precision :: r1(nmax), r2(nmax) + + logical :: debug + +! remark : the two arrays r1 and r2 are used for fourier +! transforming the user-supplied instrumental response of the +! spectrometer that has to be coded in the external routine +! respon called when the input parameter gauss is < 0 or > 1. +! with 0 <= gauss <= 1, r1 and r2 are not used. + +! *** rational approximations for ei(u) * exp(-u) + e1(u) * exp(+u) +! *** in the intervals (0, 1.3) and (1.3, infinity) <accuracy : 4.e-04> +! *** used for fourier transforming half-lorentzian functions + + +1 debug = .false. +1 data fm1 / 0.0d0 /, fp1 / 0.0d0 / +1 pi = 4 * datan(1.0d0) + +1 dwn = (wmax - wmin) / (np - 1) + +! *** redefine the frequency interval (0, wmax) to be used for the +! *** fourier transforms + +1 if (debug) write(*,*) 'wmin: ', wmin, 'wmax: ', wmax, 'dwn: ', dwn +1 jmin = int(0.5d0 + wmin / dwn) +1 if ((jmin - 0.5d0) * dwn < wmin) then +1 jmin = jmin + 1 +1 endif +1 fac = ((jmin - 0.5d0) * dwn - wmin) / dwn +1 jmax = int(0.5d0 + wmax / dwn) +1 test = dmax1(1.5d0 * dabs(emin), 1.5d0 * dabs(emax), 6 * wmax) +1 n = 2 +1 do m = 2, mmax +11 n = 2 * n +11 wmax = n * dwn +11 if (wmax >= test) exit +10 enddo +1 if (wmax < test) then +*> m = mmax +*> n = nmax +*> wmax = n * dwn +*> if (debug) write(*,*) ' +++ n has been fixed at', nmax, ' = 2**', mmax, ' +++' +*> endif +1 if (debug) then +*> write(*,*) ' classical spectrum redefined from 0.0 to', wmax +*> write(*,*) ' step size =', dwn, ', ', n, ' (= 2**', m, ') points' +*> endif + +1 allocate (p1(n)) +1 allocate (p2(n)) + +1 p1 = 0 + +! *** interpolate pcl on a suitable mesh in (0, wmax) +1 i = 1 +1 do j = jmin, min(jmax, n) +325 p1(j) = p(i) + fac * (p(i + 1) - p(i)) +325 i = i + 1 +325 enddo + +1 p2 = p1 + +! *** characteristic function f(tau) + +1 call sicot(p1, m, dwn, 1.39d0 * t) +1 call sintr(p2, m, dwn) +1 h = (pi + pi) / wmax +1 if (gauss < 0.0d0 .or. gauss > 1.0d0) then + +! *** broaden the spectrum by convoluting the characteristic function +! *** with a user-supplied response function (arbitrary normalization) + +*> if (debug) write(*,*) '==> switch to a user-supplied instrumental response' +*> alfa = dmax1(4 * dwn, width) +*> if (alfa > width) then +*> if (debug) write(*,*) ' +++ width has been enlarged to', alfa, ' +++' +*> endif +*> if (alfa < 10 * dwn) then +*> if (debug) then +*> write(*,*) ' ... poor representation of the response function ...' +*> write(*,*) 'the step size (', dwn, ') should be reduced' +*> endif +*> endif +! make a table of the response function +*> r1(1) = respon(0.0d0, alfa) +*> r2(1) = r1(1) +*> do i = 2, n +*> x = (i - 1) * dwn +*> r1(i) = respon( x, alfa) +*> r2(i) = respon(-x, alfa) +*> enddo +! fourier transform it +*> call rcffi(r1, r2, -m, dwn) +! normalization of the response function, and convolution +*> anorm = r1(1) +*> do i = 1, n +*> fac = dexp(-p1(i)) / anorm +*> cp2 = fac * dcos(p2(i)) +*> sp2 = fac * dsin(p2(i)) +*> p1(i) = r1(i) * cp2 + r2(i) * sp2 +*> p2(i) = r2(i) * cp2 - r1(i) * sp2 +*> enddo +*> alfa = alfa / 2 + +1 else + +! *** broaden the spectrum by convoluting the characteristic function by +! *** a weighted sum of a lorentzian and a gaussian response functions + +1 alfa = dmax1(1.5d0 * dwn, width) +1 if (alfa > width) then +*> if (debug) write(*,*) ' +++ width has been enlarged to', alfa, ' +++' +*> endif +1 if (alfa > 0.5d0 * wmax / pi) then +*> stop '*** width is too large, nothing done ***' +*> endif +1 alfa = 0.5d0 * alfa +1 sigma = alfa / 1.66511d0 +1 a1 = (1.0d0 - asym) / 2 * (1.0d0 - gauss) +1 a2 = (1.0d0 + asym) / 2 * (1.0d0 - gauss) +1 if (a1 < 0.0d0 .or. a2 < 0.0d0) then +*> stop '*** invalid input : asym should be in (-1, +1) ***' +*> endif +1 g1 = (1.0d0 - asym) * alfa +1 g2 = (1.0d0 + asym) * alfa +1 p1(1) = 1.0d0 +1 p2(1) = 0.0d0 +1 do i = 2, n +4095 x = (i - 1) * h +4095 fr = 0.0d0 +4095 fi = 0.0d0 +4095 if (a1 /= 0.0d0) then +4095 x1 = g1 * x +4095 if (x1 <= 100.0d0) then +4095 fr = a1 * dexp(-x1) +4095 endif +4095 if (a1 /= a2) then +4095 if (x1 <= 1.3d0) then +193 fi = a1 * o1(x1) +3902 else +3902 fi = a1 * o2(x1) +3902 endif +4095 endif +4095 endif +4095 if (a2 /= 0.0d0) then +4095 x2 = g2 * x +4095 if (x2 <= 100.0d0) then +4095 fr = fr + a2 * dexp(-x2) +4095 endif +4095 if (a2 /= a1) then +4095 if (x2 <= 1.3d0) then +104 fi = fi - a2 * o1(x2) +3991 else +3991 fi = fi - a2 * o2(x2) +3991 endif +4095 endif +4095 endif +4095 if (gauss /= 0.0d0) then +4095 x3 = sigma * x +4095 if (x3 <= 10.0d0) then +1736 fr = fr + gauss * dexp(-x3**2) +1736 endif +4095 endif +4095 fi = fi / pi +4095 fac = dexp(-p1(i)) +4095 cp2 = fac * dcos(p2(i)) +4095 sp2 = fac * dsin(p2(i)) +4095 p1(i) = fr * cp2 + fi * sp2 +4095 p2(i) = fi * cp2 - fr * sp2 +4095 enddo +1 if (dabs(fi) > 1.0d-03) then +*> if (debug) then +*> write(*,*) ' ... poor representation of the response function ...' +*> write(*,*) 'the step size (', dwn, ') should be reduced' +*> endif +*> endif +1 endif + +! *** full eels spectrum + +1 call rcffi(p1, p2, m, h) + +! *** output + +1 istep = max(int(alfa / dwn / 10), 1) +1 nout = 0 +1 if (emin <= 0.0d0) then +1 imin = n - int(dabs(emin) / dwn) +1 if ((imin - n) * dwn < emin) then +*> imin = imin + 1 +*> endif +1 do i = imin, n +251 j = n - i +251 if (mod(j, istep) > 0) cycle +251 x = -j * dwn +251 if (x > emax) exit +251 nout = nout + 1 +251 xout(nout)= x +251 yout(nout)= p2(j + 1) +251 enddo +1 endif +1 if (x <= emax) then +1 if (emax >= dwn) then +1 imax = int(emax / dwn) + 1 +1 if ((imax - 1) * dwn > emax) then +*> imax = imax - 1 +*> endif +1 if (imax >= 2) then +1 do i = 2, imax +600 if (mod(i - 1, istep) > 0) cycle +600 x = (i - 1) * dwn +600 if (x < emin) cycle +600 nout = nout + 1 +600 xout(nout) = x +600 yout(nout) = p1(i) +600 enddo +1 endif +1 endif +1 endif +1 if (debug) write(*,*) nout, ' values, step size =', istep * dwn + +! *** analyze the spectrum + +1 if (debug) write(*,*) ' peak location amplitude' +1 wn = 0.0d0 +1 fm = p1(1) +1 fp = p2(1) +1 if (p2(2) < fp .and. p1(2) < fp) then +1 if (debug) write(*, '(f13.2, e13.4)') wn, fp +1 endif +1 fac = 5.0d-06 * fp * dwn +1 imax = 2 + int(dmax1(dabs(emin), dabs(emax)) / dwn) +1 do i = 2, imax +601 fm0 = fm1 +601 fp0 = fp1 +601 fm1 = fm +601 fp1 = fp +601 fm = p2(i) +601 fp = p1(i) +601 if (i == 2) cycle +600 picm = .false. +600 picp = .false. +600 wn = (i - 1) * dwn +600 if ((fm1 >= fm0) .and. (fm1 >= fm)) then +2 a = (fm1 - fm0) + (fm1 - fm) +2 if (a >= fac) then +2 b = 0.5d0 * ((fm1 - fm0) + 3 * (fm1 - fm)) +2 u = b / a +2 wmpic = -wn + u * dwn +2 fmpic = fm + 0.5d0 * b * u +2 picm = .true. +2 endif +2 endif +600 if ((fp1 >= fp0) .and. (fp1 >= fp)) then +2 a = (fp1 - fp0) + (fp1 - fp) +2 if (a >= fac) then +2 b = 0.5d0 * ((fp1 - fp0) + 3 * (fp1 - fp)) +2 u = b / a +2 wppic = wn - u * dwn +2 fppic = fp + 0.5d0 * b * u +2 picp = .true. +2 if (picp) then +2 if (picm) then +*> if (debug) write(*, '(2(f13.2, e13.4, 5x))') wppic, fppic, wmpic, fmpic +2 else +2 if (debug) write(*, '(f13.2, e13.4)') wppic, fppic +2 endif +2 endif +2 endif +2 endif +600 if (picm .and. (.not. picp)) then +2 if (debug) write(*, '(33x, f13.2, e13.4)') wmpic, fmpic +2 endif +600 enddo +1 deallocate (p1) +1 deallocate (p2) +1 return +end subroutine doboson +double precision function o1(u) + + implicit none + + double precision, intent(in) :: u + double precision :: u2 + +297 u2 = u**2 +297 o1 = -dsinh(u) * dlog(u2) + u * ((0.03114d0 * u2 + 0.41666d0) * u2 + 0.84557d0) + +297 return +end function o1 +double precision function o2(u) + + implicit none + + double precision, intent(in) :: u + double precision :: u2 + +7893 u2 = 1 / u**2 +7893 o2 = (((202.91d0 * u2 + 932.21d0) * u2 + 41.740d0) * u2 + 2.0d0) / & + (((540.88d0 * u2 + 345.67d0) * u2 + 18.961d0) * u2 + 1.0d0) / u + +7893 return +end function o2 diff --git a/source/f90/fcat-analysis/eels_all.f90.fcat-analysis.txt b/source/f90/fcat-analysis/eels_all.f90.fcat-analysis.txt new file mode 100644 index 0000000..1feb9ef --- /dev/null +++ b/source/f90/fcat-analysis/eels_all.f90.fcat-analysis.txt @@ -0,0 +1,1353 @@ +program eels + +! ****************************************************************** +! * * +! * compute the classical eels spectrum of an arbitrary plane- * +! * statified medium made from isotropic materials in specular * +! * geometry using the dielectric theory of eels. * +! * * +! ****************************************************************** + + implicit none + + double precision :: e0, theta, phia, phib, wmin, wmax, dw + integer :: i, j, jos, k, l, layers, neps, nper, nw + logical :: user + character (len = 72) :: comment(2) + character (len = 10) :: contrl, mode + + double precision, allocatable :: thick(:), epsinf(:), osc(:, :) + integer, allocatable :: nos(:) + character (len = 10), allocatable :: name(:) + double precision, allocatable :: wn_array(:), f(:) + + integer :: old_size_1, old_size_2 + double precision, allocatable :: tmp_osc(:, :) + integer :: ioStatus + +! integer, parameter :: name_length = 10 +! *** read spectrometer parameters + +1 call change_working_dir() +1 open(unit = 11, file = 'eelsin') +! impact energy (ev) +1 read(11, *) e0 +! incidence angle (%) +1 read(11, *) theta +! angular apertures of the elliptic detector (%) +1 read(11, *) phia +1 read(11, *) phib +! energy-loss interval and step size (cm**-1) +1 read(11, *) wmin +1 read(11, *) wmax +1 read(11, *) dw +! comment lines +1 read(11, '(a72)') (comment(k), k = 1, 2) + +1 write(*,*) 'program eels (September 2020)' +1 write(*,'(a, f6.2, a, f5.1, a, f5.2, a, f5.2, a)') & + ' e0 = ', e0, ' eV, theta = ', theta, '°, phia = ', & + phia, '°, phib = ', phib, '°' +1 write(*,'(a, g11.4, a, g11.4, a, g11.4, a)') & + ' energy losses from', wmin, ' to', wmax, ', step = ', dw, ' cm**-1' +1 write(*,*) comment(1) +1 write(*,*) comment(2) + +1 if (phia <= 0.0d0 .or. phib <= 0.0d0) then +*> stop '*** wrong input ***' +*> endif +1 if (e0 <= 0.0d0 .or. theta + phia >= 90.0d0) then +*> stop '*** bad input ***' +*> endif + +! *** read target specifications + +1 read(11, *) layers, nper, mode +1 user = layers == 0 +1 if (.not. user) then +1 neps = layers +1 if (nper == -1) then +*> neps = layers + 1 +*> nper = 1 +*> write(*,*) 'the substrate is a anisotropic uniaxial material' +*> endif +1 if (layers < 0 .or. nper < 1 .or. nper > layers) then +*> stop '*** invalid target specifications ***' +*> endif +1 write(6, 101) layers, nper +1 jos = 0 +1 allocate (name(neps), thick(neps), epsinf(neps), nos(neps)) +1 do l = 1, neps +2 if (l <= layers) then +2 read(11, 102) name(l), thick(l) +2 endif +2 read(11, *) epsinf(l), nos(l) +2 write(6, 103) +2 if (nos(l) <= 0) then +*> if (l <= layers) write(6, 104) l, name(l), thick(l), epsinf(l) +*> if (l > layers) write(6, 105) epsinf(l) +2 else +2 do j = 1, nos(l) +2 if (.not. allocated(osc)) then +1 allocate(osc(3, nos(l))) +1 else if (j == 1) then + ! call extend3(osc, nos(j)) +1 old_size_1 = size(osc, 1) +1 old_size_2 = size(osc, 2) +1 allocate(tmp_osc(old_size_1, old_size_2 + nos(l))) +1 tmp_osc(1:old_size_1, 1:old_size_2) = osc +1 deallocate(osc) +1 call move_alloc(tmp_osc, osc) +1 endif +2 jos = jos + 1 +2 read(11, *) (osc(k, jos), k = 1, 3) +2 if ((j == nos(l) / 2 + 1) .and. (nos(l) > 1)) then +*> write(6, 106) +*> write(6, 107) +*> endif +2 if (j == 1) then +2 if (l <= layers) then +2 write(6, 104) l, name(l), thick(l), epsinf(l), (osc(i, jos), i = 1, 3) +*> else +*> write(6, 105) epsinf(l), (osc(i, jos), i = 1, 3) +*> endif +*> else +*> write(6, 108) (osc(i, jos), i = 1, 3) +*> endif +2 enddo +2 endif +2 enddo +1 write(*,*) +1 read(11, 102, IOSTAT = ioStatus) contrl +1 if (ioStatus /= 0) then +1 contrl = '' +1 endif +1 endif + +1 close (unit = 11) + +1 nw = 1 + int((wmax - wmin) / dw) +1 allocate (wn_array(nw), f(nw)) + +1 call doeels(e0, theta, phia, phib, wmin, wmax, dw, comment, size(comment), & + layers, neps, nper, name, size(name), thick, epsinf, nos, osc, size(osc, 2),& + contrl, mode, wn_array, f, size(wn_array)) + +1 open (unit = 12, file = 'eelsou') +1 write (12, 207) e0, theta, phia, phib, comment(1) +1 do i = 1, nw +326 write (12, 211) wn_array(i), f(i) +326 enddo +1 close (unit = 12) + +1 stop + +*> 101 format(i3, ' layer(s), nper = ', i2//' l', 2x, 'material', 7x, & + 'thickness', 5x, 'epsinf', 4x, 'wto , wp', 5x, 'q', 7x, 'gam/wto') +*> 102 format(a10, d15.5) +*> 103 format(1x, 72('-')) +*> 104 format(1x, i3, 2x, a10, g15.3, f10.4, f12.4, f10.4, f9.4) +*> 105 format(31x, f10.4, f12.4, f10.4, f9.4) +*> 106 format(45x, 'wlo , wp', 5x, 'q', 7x, 'gam/wlo') +*> 107 format(45x, 28('-')) +*> 108 format(41x, f12.4, f10.4, f9.4) +*> 207 format('e0 =', f6.2, ' theta =', f5.1, ' phia =', f5.2, ' phib =', f5.2 / a72) +*> 211 format(2e15.7) +end program eels + +double precision function qrat(x, alpha, beta, c1, c2) + + implicit none + + double precision, intent(in) :: x, alpha, beta, c1, c2 + +*> qrat = (1.0d0 + x * (beta + c1 * x)) / ((1.0d0 + x * (beta + c2 * x)) * (1.0d0 + alpha * x)**2) + +*> return +end function qrat + +double precision function usurlo(dq, wn) + +! ****************************************************************** +! * * +! * user-supplied dielectric surface loss function aimag(g(dq, wn)) * +! * input arguments : * +! * dq : modulus of the two-dimensional surface wave vector * +! * (angstroem**-1) * +! * wn : frequency (cm**-1) * +! * * +! ****************************************************************** + + implicit none + + double precision, intent(in) :: dq + double precision, intent(in) :: wn + +*> usurlo = 1.0d0 +*> return +end function usurlo +double precision function surlos(dk, eps, thick, layers, nper) + +! ****************************************************************** +! * * +! * eels surface loss function for an arbitrary multilayered target* +! * * +! ****************************************************************** + + implicit none + + double precision, intent(in) :: dk + double complex, intent(in) :: eps(:) + double precision, intent(in) :: thick(:) + integer, intent(in) :: layers, nper + + integer :: lmax + logical :: static, zero, skip + integer :: lstart, n + double precision, allocatable :: arg(:) + double precision :: argmin, argmax, cn, cnm1, epsmac, sn, snm1, tn + double complex :: a, b, csi, pnm2, pnm1, pn, pp, qnm2, qnm1, qn, qp, z + + common / mulayr / argmin, argmax, epsmac + + zero(z) = (dble(z) == 0.0d0) .and. (dimag(z) == 0.0d0) + +! write (*,*) 'surlos:' +! write (*,*) 'thick: ', size(thick) +! write (*,*) 'eps: ', size(eps) + +40156 lmax = size(eps) +40156 allocate (arg(lmax)) +40156 lstart = layers - nper + 1 +40156 static = .true. +40156 skip = .false. + +40156 do n = 1, layers +63246 arg(n) = dk * thick(n) +63246 if (arg(n) > argmax .or. zero(eps(n))) then +17169 csi = eps(n) +17169 skip = .true. +17169 exit +*> endif +46077 static = .not. (n >= lstart .and. arg(n) > argmin) +46077 enddo + +40156 if (.not. skip) then +! *** periodic continued fraction, period = nper + +22987 do ! Do loop is only for the option to skip out of it. +22987 if (nper <= 1) then +22987 csi = eps(layers) +*> else +*> if (static) then +*> pn = 0.0d0 +*> qn = 0.0d0 +*> do n = lstart, layers +*> pn = pn + thick(n) * eps(n) +*> qn = qn + thick(n) / eps(n) +*> enddo +*> if (zero(qn)) then +*> n = lstart +*> if (n <= 1) then +*> surlos = 0.0d0 +*> return +*> endif +*> n = n - 1 +*> csi = eps(n) / dtanh(arg(n)) +*> exit +*> endif ! zero(qn) +*> csi = cdsqrt(pn / qn) +*> if ((dimag(csi) < 0.0d0) .and. (dble(qn) < 0.0d0)) then +*> csi = -csi +*> endif +*> else ! static +*> cn = dcosh(arg(lstart)) +*> sn = dsinh(arg(lstart)) +*> pnm1 = 1.0d0 +*> pn = cn +*> pp = eps(lstart) * sn +*> qnm1 = 0.0d0 +*> qn = sn / eps(lstart) +*> qp = pn +*> do n = lstart + 1, layers +*> cnm1 = cn +*> snm1 = sn +*> cn = dcosh(arg(n)) +*> sn = dsinh(arg(n)) +*> a = eps(n) * sn +*> pp = cn * pp + a * pn +*> qp = cn * qp + a * qn +*> b = (eps(n - 1) / eps(n)) * (sn / snm1) +*> a = cnm1 * b + cn +*> pnm2 = pnm1 +*> pnm1 = pn +*> qnm2 = qnm1 +*> qnm1 = qn +*> pn = a * pnm1 - b * pnm2 +*> qn = a * qnm1 - b * qnm2 +*> enddo +*> if (zero(qn)) then +*> a = qp - pn +*> if (zero(a)) then +*> n = lstart +*> if (n <= 1) then +*> surlos = 0.0d0 +*> return +*> endif +*> n = n - 1 +*> csi = eps(n) / dtanh(arg(n)) +*> exit +*> endif +*> csi = pp / a +*> else +*> a = 0.5d0 * (pn - qp) / qn +*> b = cdsqrt(a**2 + pp / qn) +*> pn = a - pn / qn +*> if (cdabs(pn + b) > cdabs(pn - b)) then +*> b = -b +*> endif +*> csi = a + b +*> endif ! zero(qn) +*> endif ! static +! *** small-dk limit of the periodic tail + +*> endif ! nper <= 1 + +22987 n = lstart + +22987 exit +*> enddo +22987 endif ! .not. skip + +! *** backward algorithm + +40156 do +63246 n = n - 1 +63246 if (n <= 0) then +40156 a = csi + 1.0d0 +40156 if (zero(a)) then +*> surlos = 2 / epsmac +40156 else +40156 surlos = dimag(-2 / a) +40156 endif +40156 return +*> endif ! n <= 0 + +23090 if (arg(n) /= 0.0d0) then +23090 tn = dtanh(arg(n)) +23090 b = eps(n) + csi * tn +23090 if (zero(b)) then +*> surlos = 0.0d0 +*> return +*> endif +23090 csi = eps(n) * (csi + tn * eps(n)) / b +23090 endif +23090 enddo +end function surlos +double precision function phint(phi, a, u) + +! ****************************************************************** +! * * +! * evaluate the integral from zero to phi of * +! * * +! * u 2 * +! * ( ----------------------------- ) dphi * +! * 2 2 * +! * (1 - a * u * cos(phi)) + u * +! * * +! * for 0 <= phi <= pi , u >= 0 and a >= 0 * +! * * +! ****************************************************************** + + implicit none + + double precision, intent(in) :: phi + double precision, intent(in) :: a + double precision, intent(in) :: u + + double precision :: ai, ar, bi, br, c, cpr, d, e, esr, pi, qr, ri, rm, root + double precision :: rp, rr, s, spr, tm, tp, u2, x, zeta, zetai, zetar, zr + +41010 pi = 3.141592653589793238d0 +41010 c = dcos(phi) +41010 s = dsin(phi) +41010 u2 = u**2 +41010 e = a*u +41010 if (u < 1.0d0 .and. e < 1.0d-02 * (1.0d0 + u2)) then +*> zr = 1.0d0 + u2 +*> esr = e / zr +*> phint = u2 / zr**2 * ((( (4.0d0 / 3.0d0) * (2.0d0 + c**2) * s * (5.0d0 - 3 * u2) * & + esr + (phi + c * s) * (5.0d0 - u2)) * esr + 4 * s) * esr + phi) +41010 else +41010 rm = dsqrt((1.0d0 - e)**2 + u2) +41010 tm = 0.5d0 * datan2(u, 1.0d0 - e) +41010 rp = dsqrt((1.0d0 + e)**2 + u2) +41010 tp = 0.5d0 * datan2(u, 1.0d0 + e) +41010 root = dsqrt(rm * rp) +41010 cpr = dcos(tm + tp) +41010 spr = dsin(tm + tp) +41010 x = 0.0d0 ! ensure initialization +41010 if (c >= 0.0d0) then +20833 x = s / (1.0d0 + c) +19851 elseif (dabs(s) > 1.0d-07) then +19851 x = (1.0d0 - c) / s +19851 endif +41010 if ((c >= 0.0d0) .or. (dabs(s) > 1.0d-07)) then +40684 zeta = dsqrt(rm / rp) +40684 zetar = -zeta * dsin(tm - tp) +40684 zetai = zeta * dcos(tm - tp) +40684 br = 0.5d0 * dlog(((zetar + x)**2 + zetai**2) / ((zetar - x)**2 + zetai**2)) +40684 bi = datan2(zetai, zetar + x) - datan2(zetai, zetar - x) +40684 rr = -(br * spr - bi * cpr) / root +40684 ri = -(bi * spr + br * cpr) / root +40684 d = e * s / ((1.0d0 - e * c)**2 + u2) +40684 ar = d * (1.0d0 - e * c) - rr + u * ri +40684 ai = -d * u - ri - u * rr +326 else +326 rr = -pi / root * cpr +326 ri = pi / root * spr +326 ar = -rr + u * ri +326 ai = -ri - u * rr +326 endif +41010 qr = (ar * (cpr - spr) * (cpr + spr) + 2 * ai * cpr * spr) / (rm * rp) +41010 phint = 0.5d0 * (ri / u - qr) +41010 endif +41010 return +end function phint +double precision function fint1(u, eps, thick, layers, nper, eps_size) + +! ****************************************************************** +! * * +! * integration over the azimutal angle from 0.0 to pi * +! * * +! ****************************************************************** + + implicit none + + double precision, intent(in) :: u + integer, intent(in) :: layers, nper, eps_size + double complex, intent(in) :: eps(eps_size) + double precision, intent(in) :: thick(eps_size) + + logical :: rational, user + double precision :: acoef, bcoef, ccoef, cospsi, den, dif, dlimf, e, elleps + double precision :: pi, rom, rop, ru, sinpsi, sum, um, t + double precision :: tanpsi, wn, u2 + + interface + double precision function usurlo(dq, wn) + double precision, intent(in) :: dq + double precision, intent(in) :: wn + end function usurlo + double precision function surlos(dk, eps, thick, layers, nper) + double precision, intent(in) :: dk + double complex, intent(in) :: eps(:) + double precision, intent(in) :: thick(:) + integer, intent(in) :: layers, nper + end function surlos + end interface + + common / param / acoef, bcoef, ccoef, elleps, cospsi, sinpsi, tanpsi, & + ru, um, dlimf, wn, user, rational + + data pi / 3.141592653589793238d0 / + +! write (*,*) 'fint1:' +! write (*,*) 'thick: ', size(thick) +! write (*,*) 'eps: ', size(eps) + +14598 if (u == 0.0d0) then +326 fint1 = 0.0d0 +326 return +*> endif +14272 e = tanpsi * u +14272 u2 = u**2 +14272 rom = (1.0d0 - e)**2 + u2 +14272 rop = (1.0d0 + e)**2 + u2 +14272 sum = rop + rom +14272 rom = dsqrt(rom) +14272 rop = dsqrt(rop) +14272 dif = rop - rom +14272 den = dsqrt((2.0d0 - dif) * (2.0d0 + dif)) * rop * rom +14272 fint1 = pi * u2 * (4 * sum - dif**2 * (sum - rop * rom)) / den**3 +14272 if (rational) then +*> return +*> endif +14272 if (user) then +*> fint1 = fint1 * usurlo(ru * u, wn) +14272 else +14272 fint1 = fint1 * surlos(ru * u, eps, thick, layers, nper) +14272 if (dlimf > 0.0d0) then +*> t = ru * u * dlimf +*> fint1 = fint1 * (1.d0 + t * dlog(t / (t + 0.26d0)))**2 / (1.d0 + 1.40d0 * t) +*> endif +14272 endif +14272 return +end function fint1 +double precision function fint2(u, eps, thick, layers, nper, eps_size) + +! ****************************************************************** +! * * +! * integration over the azimutal angle from 0.0 to phi < pi * +! * * +! ****************************************************************** + + implicit none + + double precision, intent(in) :: u + integer, intent(in) :: layers, nper, eps_size + double complex, intent(in) :: eps(eps_size) + double precision, intent(in) :: thick(eps_size) + + logical :: rational, user + double precision :: a, arg, b, b2, c, ccoef, cospsi, dlimf, elleps, phi + double precision :: phint, ru, sinpsi, um, t, tanpsi, wn, x + + interface + double precision function usurlo(dq, wn) + double precision, intent(in) :: dq + double precision, intent(in) :: wn + end function usurlo + double precision function surlos(dk, eps, thick, layers, nper) + double precision, intent(in) :: dk + double complex, intent(in) :: eps(:) + double precision, intent(in) :: thick(:) + integer, intent(in) :: layers, nper + end function surlos + end interface + + common / param / a, b, ccoef, elleps, cospsi, sinpsi, tanpsi, & + ru, um, dlimf, wn, user, rational + +! write (*,*) 'fint2:' +! write (*,*) 'thick: ', size(thick) +! write (*,*) 'eps: ', size(eps) + +10758 if (u == 0.0d0) then +*> fint2 = 0.0d0 +*> return +*> endif +10758 b2 = b**2 +10758 c = (1.0d0 - elleps) * (cospsi * u)**2 + (b - ccoef) * (b + ccoef) +10758 if (dabs(a * c) > 1.0d-03 * b2) then +10758 x = (b - dsqrt(b2 - a * c)) / a +*> else +*> x = a * c / b2 +*> x = 0.5d0 * c * (1.d0 + 0.25d0 * x * (1.d0 + 0.5d0 * x * (1.d0 + 0.625d0 * x))) / b +*> endif +10758 arg = x / u +10758 if (dabs(arg) > 1.0d0) then +74 arg = dsign(1.0d0, arg) +74 endif +10758 phi = dacos(arg) +10758 fint2 = phint(phi, tanpsi, u) +10758 if (rational) then +*> return +*> endif +10758 if (user) then +*> fint2 = fint2 * usurlo(ru * u, wn) +10758 else +10758 fint2 = fint2 * surlos(ru * u, eps, thick, layers, nper) +10758 if (dlimf > 0.0d0) then +*> t = ru * u * dlimf +*> fint2 = fint2 * (1.d0 + t * dlog(t / (t + 0.26d0)))**2 / (1.d0 + 1.40d0 * t) +*> endif +10758 endif +10758 return +end function fint2 +double precision function fint3(u, eps, thick, layers, nper, eps_size) + +! ****************************************************************** +! * * +! * integration over the azimutal angle from phi1 > 0 to phi2 < pi * +! * * +! ****************************************************************** + + implicit none + + double precision, intent(in) :: u + integer, intent(in) :: layers, nper, eps_size + double complex, intent(in) :: eps(eps_size) + double precision, intent(in) :: thick(eps_size) + + logical :: rational, user + double precision :: a, arg, b, ccoef, cospsi, dlimf, elleps, phi1, phi2 + double precision :: phint, sinpsi, rac, ru, um, t, tanpsi, wn + + interface + double precision function usurlo(dq, wn) + double precision, intent(in) :: dq + double precision, intent(in) :: wn + end function usurlo + double precision function surlos(dk, eps, thick, layers, nper) + double precision, intent(in) :: dk + double complex, intent(in) :: eps(:) + double precision, intent(in) :: thick(:) + integer, intent(in) :: layers, nper + end function surlos + end interface + + common / param / a, b, ccoef, elleps, cospsi, sinpsi, tanpsi, & + ru, um, dlimf, wn, user, rational + +! write (*,*) 'fint3:' +! write (*,*) 'thick: ', size(thick) +! write (*,*) 'eps: ', size(eps) + +15126 if (u == 0.0d0) then +*> fint3 = 0.0d0 +*> return +*> endif +15126 rac = dsign(1.0d0, a) * cospsi * dsqrt((1.0d0 - elleps) * a * (um - u) * (um + u)) +15126 arg = (b - rac) / (u * a) +15126 if (dabs(arg) > 1.0d0) arg = dsign(1.0d0, arg) +15126 phi2 = dacos(arg) +15126 fint3 = phint(phi2, tanpsi, u) +15126 arg = (b + rac) / (u * a) +15126 if (dabs(arg) > 1.0d0) arg = dsign(1.0d0, arg) +15126 phi1 = dacos(arg) +15126 fint3 = fint3 - phint(phi1, tanpsi, u) +15126 if (rational) return +15126 if (user) then +*> fint3 = fint3 * usurlo(ru * u, wn) +15126 else +15126 fint3 = fint3 * surlos(ru * u, eps, thick, layers, nper) +15126 if (dlimf > 0.0d0) then +*> t = ru * u * dlimf +*> fint3 = fint3 * (1.d0 + t * dlog(t / (t + 0.26d0)))**2 / (1.d0 + 1.40d0 * t) +*> endif +15126 endif +15126 return +end function fint3 +double precision function fun(phi) + +! ****************************************************************** +! * * +! * integrand of the expression of the 1st order term in the * +! * expansion of the eels integral for a homogeneous target. * +! * * +! ****************************************************************** + + implicit none + + double precision, intent(in) :: phi + + logical :: user, rational + double precision :: acoef, bcoef, ccoef, cospsi, dlimf, elleps, ru + double precision :: sinphi, sinpsi, tanpsi, um, wn + + common / param / acoef, bcoef, ccoef, elleps, cospsi, sinpsi, tanpsi, & + ru, um, dlimf, wn, user, rational + +*> sinphi = dsin(phi) +*> fun = dsqrt((1.0d0 - elleps + elleps * sinphi**2) * & + (1.0d0 - sinpsi * sinphi) * & + (1.0d0 + sinpsi * sinphi)) +*> return +end function fun +subroutine quanc8(fun, a, b, abserr, relerr, result, errest, nofun, flag, eps, thick, layers, nper) + +! estimate the integral of fun(x) from a to b +! to a user provided tolerance. +! an automatic adaptive routine based on +! the 8-panel newton-cotes rule (g. forsythe et al, 1977, p. 92) +! +! input .. +! +! fun the name of the integrand function subprogram fun(x). +! a the lower limit of integration. +! b the upper limit of integration.(b may be less than a.) +! relerr a relative error tolerance. (should be non-negative) +! abserr an absolute error tolerance. (should be non-negative) +! +! output .. +! +! result an approximation to the integral hopefully satisfying the +! least stringent of the two error tolerances. +! errest an estimate of the magnitude of the actual error. +! nofun the number of function values used in calculation of result. +! flag a reliability indicator. if flag is zero, then result +! probably satisfies the error tolerance. if flag is +! xxx.yyy , then xxx = the number of intervals which have +! not converged and 0.yyy = the fraction of the interval +! left to do when the limit on nofun was approached. + + implicit none + + double precision :: fun + double precision, intent(in) :: a + double precision, intent(in) :: b + double precision, intent(in out) :: abserr + double precision, intent(in) :: relerr + double precision, intent(out) :: result + double precision, intent(out) :: errest + integer, intent(out) :: nofun + double precision, intent(out) :: flag + + external fun + + double precision, intent(in) :: thick(:) + double complex, intent(in) :: eps(:) + integer, intent(in) :: layers, nper + + double precision :: w0, w1, w2, w3, w4, area, x0, f0, stone, step, cor11, temp + double precision :: qprev, qnow, qdiff, qleft, esterr, tolerr + double precision :: qright(31), f(16), x(16), fsave(8, 30), xsave(8, 30) + double precision :: dabs, dmax1 + + integer :: levmin, levmax, levout, nomax, nofin, lev, nim, i, j + +! *** stage 1 *** general initialization +! set constants. + +! write (*,*) 'quanc8:' +! write (*,*) 'thick: ', size(thick) +! write (*,*) 'eps: ', size(eps) + +978 levmin = 1 +978 levmax = 30 +978 levout = 6 +978 nomax = 5000 +978 nofin = nomax - 8 * (levmax - levout + 2**(levout + 1)) + +! trouble when nofun reaches nofin + +978 w0 = 3956.0d0 / 14175.0d0 +978 w1 = 23552.0d0 / 14175.0d0 +978 w2 = -3712.0d0 / 14175.0d0 +978 w3 = 41984.0d0 / 14175.0d0 +978 w4 = -18160.0d0 / 14175.0d0 + +! initialize running sums to zero. + +978 flag = 0.0d0 +978 result = 0.0d0 +978 cor11 = 0.0d0 +978 errest = 0.0d0 +978 area = 0.0d0 +978 nofun = 0 +978 if (a == b) return + +! *** stage 2 *** initialization for first interval + +978 lev = 0 +978 nim = 1 +978 x0 = a +978 x(16) = b +978 qprev = 0.0d0 +978 f0 = fun(x0, eps, thick, layers, nper, size(eps)) +978 stone = (b - a) / 16 +978 x(8) = (x0 + x(16)) / 2 +978 x(4) = (x0 + x(8)) / 2 +978 x(12) = (x(8) + x(16)) / 2 +978 x(2) = (x0 + x(4)) / 2 +978 x(6) = (x(4) + x(8)) / 2 +978 x(10) = (x(8) + x(12)) / 2 +978 x(14) = (x(12) + x(16)) / 2 +978 do j = 2, 16, 2 +7824 f(j) = fun(x(j), eps, thick, layers, nper, size(eps)) +7824 enddo +978 nofun = 9 + +978 do + +! *** stage 3 *** central calculation +! requires qprev, x0, x2, x4, ..., x16, f0, f2, f4, ..., f16. +! calculates x1, x3, ...x15, f1, f3, ...f15, qleft, qright, qnow, qdiff, area. + +3960 x(1) = (x0 + x(2)) / 2 +3960 f(1) = fun(x(1), eps, thick, layers, nper, size(eps)) +3960 do j = 3, 15, 2 +27720 x(j) = (x(j - 1) + x(j + 1)) / 2 +27720 f(j) = fun(x(j), eps, thick, layers, nper, size(eps)) +27720 enddo +3960 nofun = nofun + 8 +3960 step = (x(16) - x0) / 16.0d0 +3960 qleft = (w0 * (f0 + f(8)) + w1 * (f(1) + f(7)) + w2 * (f(2) + f(6)) & + + w3 * (f(3) + f(5)) + w4 * f(4)) * step +3960 qright(lev + 1) = (w0 * (f(8) + f(16)) + w1 * (f(9) + f(15)) + w2 * (f(10) + f(14)) & + + w3 * (f(11) + f(13)) + w4 * f(12)) * step +3960 qnow = qleft + qright(lev + 1) +3960 qdiff = qnow - qprev +3960 area = area + qdiff + +! *** stage 4 *** interval convergence test + +3960 esterr = dabs(qdiff) / 1023 +3960 tolerr = dmax1(abserr, relerr * dabs(area)) * (step / stone) + +3960 if (lev >= levmin) then +2982 if (lev >= levmax) then +! current level is levmax. +*> flag = flag + 1.0d0 +2982 else +2982 if (nofun > nofin) then +! *** stage 6 *** trouble section +! number of function values is about to exceed limit. +*> nofin = 2 * nofin +*> levmax = levout +*> flag = flag + (b - x0) / (b - a) +2982 else +2982 if (esterr > tolerr) then +! *** stage 5 *** no convergence +! locate next interval. +513 nim = 2 * nim +513 lev = lev + 1 +! store right hand elements for future use. +513 do i = 1, 8 +4104 fsave(i, lev) = f(i + 8) +4104 xsave(i, lev) = x(i + 8) +4104 enddo +! assemble left hand elements for immediate use. +513 qprev = qleft +513 do i = 1, 8 +4104 f(18 - 2 * i) = f(9 - i) +4104 x(18 - 2 * i) = x(9 - i) +4104 enddo +513 cycle +*> endif +2469 endif +2469 endif + +! *** stage 7 *** interval converged +! add contributions into running sums. +2469 result = result + qnow +2469 errest = errest + esterr +2469 cor11 = cor11 + qdiff / 1023 +! locate next interval. +2469 do while (nim /= 2 * (nim / 2)) +2469 nim = nim / 2 +2469 lev = lev - 1 +2469 enddo +2469 nim = nim + 1 + +2469 if (lev <= 0) exit + +! assemble elements required for the next interval. +1491 qprev = qright(lev) +1491 x0 = x(16) +1491 f0 = f(16) +1491 do i = 1, 8 +11928 f(2*i) = fsave(i, lev) +11928 x(2*i) = xsave(i, lev) +11928 enddo +1491 cycle +978 else +! *** stage 5 *** no convergence +! locate next interval. +978 nim = 2 * nim +978 lev = lev + 1 +! store right hand elements for future use. +978 do i = 1, 8 +7824 fsave(i, lev) = f(i + 8) +7824 xsave(i, lev) = x(i + 8) +7824 enddo +! assemble left hand elements for immediate use. +978 qprev = qleft +978 do i = 1, 8 +7824 f(18 - 2 * i) = f(9 - i) +7824 x(18 - 2 * i) = x(9 - i) +7824 enddo +978 endif + +978 enddo + + ! *** stage 8 *** finalize and return +978 result = result + cor11 + +! make sure errest not less than roundoff level. +978 if (errest /= 0.0d0) then +978 temp = dabs(result) + errest +978 do while (temp == dabs(result)) +*> errest = 2 * errest +*> temp = dabs(result) + errest +*> enddo +978 endif +978 return +end subroutine quanc8 +subroutine queels(x, f, aerr, rerr, facru, eps, thick, layers, nper) + +! ****************************************************************** +! * * +! * perform q-space integration for computing the eels spectrum of * +! * a isotropic target using polar coordinates. * +! * * +! * x is the dimensionless energy loss hbar*omega/(2*e0*phia) * +! * aerr and rerr are the desired absolute and relative accuracies * +! * facru*x is the units of wavevectors omega/v_perpendicular * +! * f is the q-integral multiplied by (2/pi)**2 * +! * * +! ****************************************************************** + + implicit none + + double precision, intent(in) :: x + double precision, intent(out) :: f + double precision, intent(in out) :: aerr + double precision, intent(in out) :: rerr + double precision, intent(in) :: facru + double complex, intent(in) :: eps(:) + double precision, intent(in) :: thick(:) + integer, intent(in) :: layers, nper + + logical :: rational, user + double precision :: acoef, bcoef, ccoef, cospsi, dlimf, elleps + double precision :: error, flag, ru, sinpsi + double precision :: u1, u2, um, ut, tanpsi, wn, y + integer :: ie, nofu + dimension error(3), flag(3) + + interface + double precision function fint1(u, eps, thick, layers, nper, eps_size) + double precision, intent(in) :: u + integer, intent(in) :: layers, nper, eps_size + double complex, intent(in) :: eps(eps_size) + double precision, intent(in) :: thick(eps_size) + end function fint1 + double precision function fint2(u, eps, thick, layers, nper, eps_size) + double precision, intent(in) :: u + integer, intent(in) :: layers, nper, eps_size + double complex, intent(in) :: eps(eps_size) + double precision, intent(in) :: thick(eps_size) + end function fint2 + double precision function fint3(u, eps, thick, layers, nper, eps_size) + double precision, intent(in) :: u + integer, intent(in) :: layers, nper, eps_size + double complex, intent(in) :: eps(eps_size) + double precision, intent(in) :: thick(eps_size) + end function fint3 + subroutine quanc8(fun, a, b, abserr, relerr, result, errest, nofun, flag, eps, thick, layers, nper) + double precision :: fun + double precision, intent(in) :: a + double precision, intent(in) :: b + double precision, intent(in out) :: abserr + double precision, intent(in) :: relerr + double precision, intent(out) :: result + double precision, intent(out) :: errest + integer, intent(out) :: nofun + double precision, intent(out) :: flag + + external fun + + double precision, intent(in) :: thick(:) + double complex, intent(in) :: eps(:) + integer, intent(in) :: layers, nper + end subroutine quanc8 + end interface + + common / param / acoef, bcoef, ccoef, elleps, cospsi, sinpsi, tanpsi, & + ru, um, dlimf, wn, user, rational + +! write (*,*) 'queels:' +! write (*,*) 'eps: ', size(eps) +! write (*,*) 'thick: ', size(thick) + +326 f = 0.0d0 +326 if (x <= 0.0d0) then +*> return +*> endif +326 ru = facru * x +326 ccoef = cospsi**2 / x +326 ut = ccoef - bcoef +326 u1 = dabs(ut) +326 u2 = ccoef + bcoef +326 if (ut > 0.0d0) then +326 call quanc8(fint1, 0.0d0, u1, aerr, rerr, y, error(1), nofu, flag(1), eps, thick, layers, nper) +326 f = y +*> else +*> flag(1) = 0.0d0 +*> endif +326 if (u2 > u1) then +326 call quanc8(fint2, u1, u2, aerr, rerr, y, error(2), nofu, flag(2), eps, thick, layers, nper) +326 f = f + y +*> else +*> flag(2) = 0.0d0 +*> endif +326 if (dabs(acoef) > x * (1.0d0 - elleps) * bcoef) then +326 um = dsqrt(ccoef / x / (1.0d0 - elleps) + bcoef**2 / acoef) +326 if (um > u2) then +326 call quanc8(fint3, u2, um, aerr, rerr, y, error(3), nofu, flag(3), eps, thick, layers, nper) +326 f = f + y +326 endif +326 if (um < u1) then +*> call quanc8(fint3, um, u1, aerr, rerr, y, error(3), nofu, flag(3), eps, thick, layers, nper) +*> f = f - y +*> endif +*> else +*> flag(3) = 0.0d0 +*> endif +326 do ie = 1, 3 +978 if (flag(ie) == 0.0d0) cycle +*> write(*,*) ' +++ flag(', ie, ') =', flag(ie), ', error =', error(ie), ' +++' +*> if (flag(ie) - aint(flag(ie)) > 0.5d-02) then +*> stop '*** execution aborted ***' +*> endif +*> enddo +326 f = (2 / 3.141592653589793238d0)**2 * f +326 return +end subroutine queels +subroutine seteps(neps, nos, osc, epsinf, wn, name, eps, layers, mode) + +! ****************************************************************** +! * * +! * set up long-wavelength dielectric functions of the layers for * +! * the present frequency wn (in cm**-1) * +! * * +! ****************************************************************** + + implicit none + integer, intent(in) :: neps + integer, intent(in) :: nos(:) + double precision, intent(in) :: osc(:, :) + double precision, intent(in) :: epsinf(:) + double precision, intent(in) :: wn + character (len=10), intent(in) :: name(:) + character (len=10), intent(in) :: mode + + double complex, intent(in out) :: eps(:) + integer, intent(in) :: layers + + double precision :: argmin, argmax, epsmac, x + double complex :: deno, nomi + integer :: j, k, l, m + + common / mulayr / argmin, argmax, epsmac + +! write (*,*) 'seteps:' +! write (*,*) 'nos: ', size(nos) +! write (*,*) 'osc: ', size(osc) +! write (*,*) 'epsinf: ', size(epsinf) +! write (*,*) 'name: ', size(name) +! write (*,*) 'eps: ', size(eps) +! write (*,*) 'thick: ', size(thick) + +326 j = 0 +326 do l = 1, neps +652 m = nos(l)/2 +652 nomi = dcmplx(1.0d0, 0.0d0) +652 deno = dcmplx(1.0d0, 0.0d0) +652 if (mode == 'kurosawa') then +*> do k = 1, m +*> j = j + 1 +! since osc(1,*) and wn are real, the following should be equivalent +! Check required. +! Furthermore the first term can be rewritten as +! (osc(1, j + m) - wn) * (osc(1, j + m) + wn) +! nomi = nomi * cmplx(osc(1, j + m)**2 - wn**2, - wn * osc(3, j + m)) +*> nomi = nomi * (osc(1, j + m)**2 - wn**2 - dcmplx(0.0d0, wn * osc(3, j + m))) +*> deno = deno * (osc(1, j )**2 - wn**2 - dcmplx(0.0d0, wn * osc(3, j ))) +*> enddo +*> eps(l) = epsinf(l) * nomi / deno +*> elseif (name(l) == 'metal') then +*> j = j + 1 +! suggestion for replacement +! eps(l) = -osc(1, j)**2 / cmplx(wn**2, wn * osc(3, j)) +*> eps(l) = -osc(1, j)**2 / ( wn**2 + dcmplx(0.0d0, wn * osc(3, j)) ) +652 else +652 eps(l) = epsinf(l) +! The original version had this additional loop. It seems, it has been removed +! because all cases of nos(l) > 1 are treated in case 1 above +652 do k = 1, nos(l) +652 j = j + 1 +652 x = wn / osc(1, j) +652 deno = x * dcmplx(x, osc(3, j)) +652 if (osc(2, j) >= 0.0d0) then +326 deno = 1.0d0 - deno +326 endif +652 if (cdabs(deno) == 0.0d0) then +*> deno = epsmac +*> endif +652 eps(l) = eps(l) + osc(2, j) / deno +652 enddo +652 endif +652 enddo +326 if (neps == layers + 1) then +! the substrate is a anisotropic uniaxial material +*> eps(layers) = cdsqrt(eps(layers) * eps(layers + 1)) +*> if (dimag(eps(layers)) < 0.0d0) then +*> eps(layers) = -eps(layers) +*> endif +*> endif +326 return +end subroutine seteps +subroutine doeels (e0, theta, phia, phib, wmin, wmax, dw, comment, comment_size, & + layers, neps, nper, name, name_size, thick, epsinf, nos, osc, osc_size,& + contrl, mode, wn_array, f_array, wn_array_size) + +! ****************************************************************** +! * * +! * compute the classical eels spectrum of an arbitrary plane- * +! * statified medium made from isotropic materials in specular * +! * geometry using the dielectric theory of eels. * +! * * +! ****************************************************************** + + implicit none + + integer, parameter :: nt = 5 + + double precision, intent(in) :: e0, theta, phia, phib, wmin, wmax, dw + character (len = 72) :: comment(comment_size) + character (len = 10) :: name(name_size) + double precision, intent(in) :: thick(name_size), epsinf(name_size), osc(3, osc_size) + character (len = 10) :: contrl, mode + integer, intent(in) :: comment_size, name_size, osc_size, wn_array_size + integer, intent(in out) :: layers, nper, nos(name_size) + double precision, intent(in out) :: wn_array(wn_array_size), f_array(wn_array_size) + + logical :: rational, user, debug + integer :: i, iw, neps, nofu, nout, nw, lmax + double precision :: a, acoef, aerr, alpha, argmin, argmax, b, bcoef, beta, & + c1, c2, ccoef, cospsi, dlimf, dx, elleps, ener, epsmac, facru, f, f0, & + f1, fpic, fun, pi, prefac, psia, psii, qrat, rerr, ru, sinpsi, t, & + tanpsi, table, um, widt, wn, wpic, x, xmin, xmax, z, z1, z2 + double complex, allocatable :: eps(:) + dimension table(nt) + + external fun, qrat + + interface + subroutine queels(x, f, aerr, rerr, facru, eps, thick, layers, nper) + double precision, intent(in) :: x + double precision, intent(out) :: f + double precision, intent(in out) :: aerr + double precision, intent(in out) :: rerr + double precision, intent(in) :: facru + double complex, intent(in) :: eps(:) + double precision, intent(in) :: thick(:) + integer, intent(in) :: layers, nper + end subroutine queels + subroutine seteps(neps, nos, osc, epsinf, wn, name, eps, layers, mode) + integer, intent(in) :: neps + integer, intent(in) :: nos(:) + double precision, intent(in) :: osc(:, :) + double precision, intent(in) :: epsinf(:) + double precision, intent(in) :: wn + character (len=10), intent(in) :: name(:) + character (len=10), intent(in) :: mode + double complex, intent(in out) :: eps(:) + integer, intent(in) :: layers + end subroutine seteps + subroutine quanc8(fun, a, b, abserr, relerr, result, errest, nofun, flag, eps, thick, layers, nper) + double precision :: fun + double precision, intent(in) :: a + double precision, intent(in) :: b + double precision, intent(in out) :: abserr + double precision, intent(in) :: relerr + double precision, intent(out) :: result + double precision, intent(out) :: errest + integer, intent(out) :: nofun + double precision, intent(out) :: flag + + external fun + + double precision, intent(in) :: thick(:) + double complex, intent(in) :: eps(:) + integer, intent(in) :: layers, nper + end subroutine quanc8 + end interface + + common / param / acoef, bcoef, ccoef, elleps, cospsi, sinpsi, tanpsi, & + ru, um, dlimf, wn, user, rational + common / mulayr / argmin, argmax, epsmac + + data aerr / 0.0d0 /, rerr / 1.0d-06 /, f / 0.0d0 /, f1 / 0.0d0 / + +1 debug = .false. +1 if (debug) then +*> write (*,*) 'doeels:' +*> write (*,*) 'comment: ', size(comment) +*> write (*,*) 'name: ', size(name) +*> write (*,*) 'thick: ', size(thick) +*> write (*,*) 'epsinf: ', size(epsinf) +*> write (*,*) 'osc: ', size(osc), size(osc, 1), size(osc, 2) +*> write (*,*) 'nos: ', size(nos) +*> write (*,*) 'wn_array: ', size(wn_array) +*> write (*,*) 'f_array: ', size(f_array) +*> endif + +! *** machine-dependent constants +! *** epsmac + 1.0 = epsmac , cosh(argmin) = 1.0 , tanh(argmax) = 1.0 + +1 pi = 4 * datan(1.0d0) +1 epsmac = 1.0d0 +1 do while (1.0d0 + epsmac > 1.0d0) +53 epsmac = epsmac / 2 +53 enddo +1 argmin = dsqrt(2 * epsmac) +1 argmax = 0.5d0 * dlog(2 / epsmac) + +1 dlimf = 0.0d0 +1 rational = .false. + +! *** read target specifications + +1 user = layers == 0 +1 if (user) then + +*> if (layers == 1) rational = .true. +*> if (contrl == 'image') then +! *** image-charge screening factor +*> if (layers == 1 .and. neps == 2) then +*> dlimf = dsqrt(epsinf(1) * epsinf(2)) +*> else +*> dlimf = epsinf(1) +*> endif +*> dlimf = (dlimf - 1.0d0) / (dlimf + 1.0d0) +*> endif +*> endif + +! *** initialize constants + +1 lmax = size(thick) +1 nw = size(wn_array) +1 if (debug) write (*,*) 'lmax: ', lmax +1 allocate(eps(lmax)) +1 if (debug) write (*,*) 'eps: ', size(eps) +1 nout = 1 + nw / 20 +1 ener = 8065 * e0 +1 psia = phia / 180 * pi +1 psii = theta / 180 * pi +1 cospsi = dcos(psii) +1 sinpsi = dsin(psii) +1 tanpsi = dtan(psii) +1 prefac = dsqrt(255500 / e0)/(137 * cospsi) +1 facru = psia / cospsi * dsqrt(0.2624664d0 * e0) +1 elleps = (1.0d0 - phia / phib) * (1.0d0 + phia / phib) +1 acoef = sinpsi**2 + elleps * cospsi**2 +1 bcoef = sinpsi * cospsi +1 if (dlimf > 0.0d0) then +*> rational = .false. +*> if (debug) write(*,*) ' = > electron attracted by an image charge = ', dlimf +! *** dlimf : half the length unit imposed by the image force +*> dlimf = 1.80d0 * dlimf/(e0 * cospsi**2) +*> endif +1 if (debug) write (*,*) 'rational: ', rational +1 if (rational) then + +! *** set up coefficients for the rational approximation to the integral + +*> if (debug) write(*,*) ' = > set up a rational approximation to the integral' +*> call quanc8(fun, 0.0d0, pi / 2, aerr, rerr, alpha, c1, nofu, c2, eps, thick, layers, nper) +*> alpha = (2 / pi)**2 * alpha +*> c1 = 2 / pi / dsqrt(1.0d0 - elleps) * sinpsi * alpha**2 +*> if (c1 > 0.99d0) then +*> if (debug) write(*,*) ' ===> cannot do it' +*> rational = .false. +*> else +*> c2 = 3 * alpha**2 / (1.0d0 - c1) +*> c1 = c1 * c2 +*> xmin = wmin / (2 * ener * psia) +*> xmax = wmax / (2 * ener * psia) +*> if (xmin <= 0.0d0) xmin = 0.0d0 +*> dx = dmax1(0.02d0, (xmax - xmin) / nt) +*> z1 = 0.0d0 +*> z2 = 0.0d0 +*> do i = 1, nt +*> x = xmin + i * dx +*> call queels(x, f, aerr, rerr, facru, eps, thick, layers, nper) +*> table(i) = f +*> f = f * (1.0d0 + alpha * x)**2 +*> if (dabs(c2 * f - c1) < c2 * rerr) cycle +*> z = (1.0d0 - f) / (c2 * f - c1) +*> if (z <= 0.0d0) cycle +*> z1 = z1 + x * z * (x**2 - z) +*> z2 = z2 + (x * z)**2 +*> enddo +*> if (z2 == 0.0d0) then +*> if (debug) write(*,*) ' ===> cannot do it' +*> rational = .false. +*> else +*> beta = z1 / z2 +*> z = 0.0d0 +*> do i = 1, nt +*> x = xmin + i * dx +*> z = z + (table(i) - qrat(x, alpha, beta, c1, c2))**2 +*> enddo +*> z = dsqrt(z) / nt +*> if (z > 5.0d-03) then +*> if (debug) write(*,*) ' ===> cannot do it' +*> rational = .false. +*> else +*> if (debug) write(*, 100) alpha, c1, c2, beta, z +*> endif ! z > 5.0d-03 +*> endif ! z2 == 0.0d0 +*> endif ! c1 > 0.99d0 +*> endif ! rational + +! *** loop over the energy losses + +1 if (debug) write(*, 110) +1 do iw = 1, nw +326 f0 = f1 +326 f1 = f +326 f = 0.0d0 +326 wn = wmin + (iw - 1) * dw +! if (debug) write (*,*) 'wn: ', wn +326 if (wn >= 0.0d0) then +326 if (wn /= 0.0d0) then +326 if (.not. user) call seteps(neps, nos, osc, epsinf, wn, name, eps, layers, mode) + +326 x = wn / (2 * ener * psia) +326 if (rational) then +*> f = qrat(x, alpha, beta, c1, c2) * dimag(-2 / (1.0d0 + eps(1))) +326 else +326 call queels(x, f, aerr, rerr, facru, eps, thick, layers, nper) +326 endif +326 f = prefac * f / wn +326 endif ! wn /= 0.0d0 + +326 wn_array(iw) = wn +326 f_array(iw) = f + +! *** localize a peak using a parabolic interpolation + +326 if ((iw >= 3) .and. (f1 - f0 > aerr) .and. (f1 - f > aerr)) then +2 a = (f1 - f0) + (f1 - f) +2 if (a > 4 * rerr * f1) then +2 b = 0.5d0 * (f1 - f0 + 3 * (f1 - f)) +2 t = b / a +2 wpic = wn - t * dw +2 fpic = f + 0.5d0 * b * t +2 widt = dsqrt(8 * fpic / a) * dw +2 if (debug) write(*, 120) wpic, fpic, widt +2 endif ! a > 4 * rerr * f1 +2 endif ! iw >= 3 ... +326 endif ! wn >= 0.0d0 +326 if (mod(iw, nout) == 0) then +19 if (debug) write(*, 130) 100 * iw / nw, wn, f +19 endif +326 enddo +1 return +*> 100 format(5x, 'alpha = ', f9.4, 4x, 'c1 = ', f9.4, 4x, 'c2 = ', f9.4, 4x, & + 'beta = ', f9.4/5x, 'accuracy = ', e9.2) +*> 110 format(//' run (%) wn (cm**-1) pcl(wn) (cm) |', & + ' peak location amplitude width') +*> 120 format(40x, f10.2, d12.4, f10.2) +*> 130 format(2x, f5.1, 3x, f11.3, d14.5) +end subroutine doeels +subroutine change_working_dir() + +! This routine gets the first argument of the commandline and takes it +! as the path to change the working directory +! used intrinsic routines: +! iarg returns the number of commandline arguments without the program cname. +! chdir changes the directory and returns 0 on success. +! trim removes blanks from strings. + + character (len = 256) :: argument + integer :: status + +1 if (iargc() == 1) then +*> call getarg(1, argument) +*> status = chdir(trim(argument)) +*> if (status /= 0) then +*> write (*,*) '*** change directory failed ***' +*> write (*,*) 'directory tried: ', trim(argument) +*> write (*,*) 'error code (see: man chdir): ', status +*> write (*,*) 'continuing in the start directory' +*> end if +*> end if + +1 return +end subroutine change_working_dir -- GitLab