Skip to content

Commit 27710aa

Browse files
committed
Added "automatic integration" via Gauss quadrature
1 parent 9fbcf1b commit 27710aa

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ version = "0.1.0"
77
ElectricFields = "2f84ce32-9bb1-11e8-0d9f-3dce90a4beca"
88
FastGaussQuadrature = "442a2c76-b920-505d-bb47-c5924d526838"
99
HCubature = "19dc6840-f33b-545b-b366-655c7e3ffd49"
10+
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
1011
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1112
ProgressLogging = "33c8b6b6-d38a-422a-b730-caa89a2f386c"
1213
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"

src/StrongFieldApproximation.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module StrongFieldApproximation
33
using ElectricFields
44
using Unitful
55
using UnitfulAtomic
6+
67
using FastGaussQuadrature
8+
using IntervalSets
79

810
using LinearAlgebra
911
using StaticArrays
@@ -18,6 +20,7 @@ include("momentum_grid.jl")
1820

1921
include("units.jl")
2022
include("field.jl")
23+
include("automatic_integration.jl")
2124
include("volkov.jl")
2225

2326
include("channels.jl")

src/automatic_integration.jl

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
struct ComplexPlane{T,R<:AbstractRange{T}} <: AbstractMatrix{Complex{T}}
2+
re::R
3+
im::R
4+
end
5+
6+
Base.length(p::ComplexPlane) = length(p.re)*length(p.im)
7+
Base.size(p::ComplexPlane) = (length(p.im), length(p.re))
8+
Base.eltype(p::ComplexPlane) = complex(eltype(p.re))
9+
Base.getindex(p::ComplexPlane, i::CartesianIndex) = p.re[i[2]] + im*p.im[i[1]]
10+
11+
function primitive_integral(f, a, b, c, w)
12+
μ = (a+b)/2
13+
δ = (b-a)/2
14+
v = zero(f(a))
15+
for (c,w) in zip(c,w)
16+
v += w*f*c + μ)
17+
end
18+
δ*v
19+
end
20+
21+
interval(x::AbstractRange, r::UnitRange) = x[r[1]]..x[r[end]]
22+
23+
function split_range(r::UnitRange)
24+
n = length(r)
25+
n < 1 && error("Too small range")
26+
n == 1 && return (r, r[1]:(r[1]-1))
27+
28+
s = n ÷ 2
29+
r[1]:r[s], r[s+1]:r[end]
30+
end
31+
32+
function find_closest(x::AbstractRange, x₀::Real)
33+
cur = firstindex(x):lastindex(x)
34+
i = 0
35+
while length(cur) > 1 && i < ceil(Int, log2(length(x)))
36+
left,right = split_range(cur)
37+
if x₀ interval(x, left)
38+
cur = left
39+
continue
40+
elseif x₀ interval(x, right)
41+
cur = right
42+
continue
43+
end
44+
x₀ < x[left[1]] && return left[1]
45+
x₀ > x[right[end]] && return right[end]
46+
return norm(x[left[end]]-x₀) < norm(x[right[1]]-x₀) ? left[end] : right[1]
47+
i += 1
48+
end
49+
cur[1]
50+
end
51+
52+
function find_closest(x::ComplexPlane, x₀::Number)
53+
j = find_closest(x.re, real(x₀))
54+
i = find_closest(x.im, imag(x₀))
55+
CartesianIndex((i,j))
56+
end
57+
58+
struct AutomaticIntegration{Func, Grid, Xt, GridIntegrals,
59+
Roots, Weights}
60+
f::Func
61+
x::Grid
62+
x₀::Xt
63+
∫f::GridIntegrals
64+
c::Roots
65+
w::Weights
66+
end
67+
68+
function integrate!(ai::AutomaticIntegration{<:Any,<:AbstractRange}, i)
69+
a,b = firstindex(ai.x),lastindex(ai.x)
70+
for j = i+1:b
71+
ai.∫f[j] = ai(ai.x[j],i=j-1)
72+
end
73+
for j = i-1:-1:a
74+
ai.∫f[j] = ai(ai.x[j],i=j+1)
75+
end
76+
end
77+
78+
function integrate!(ai::AutomaticIntegration{<:Any,<:ComplexPlane}, i)
79+
s = size(ai.x)
80+
ci = CartesianIndices(s)
81+
82+
north(I::CartesianIndex) = CartesianIndex(I[1]-1,I[2])
83+
south(I::CartesianIndex) = CartesianIndex(I[1]+1,I[2])
84+
west(I::CartesianIndex) = CartesianIndex(I[1],I[2]-1)
85+
east(I::CartesianIndex) = CartesianIndex(I[1],I[2]+1)
86+
87+
# First, we integrate parallel to the real axis, starting from
88+
# index i, then we integrate parallel to the imaginary axis,
89+
# starting from the real line-parallel we just created.
90+
for (r,dir) in [(reverse(ci[i[1],1:i[2]-1]), east),
91+
(ci[i[1],i[2]+1:end], west),
92+
(ci[i[1]+1:end,:], north),
93+
(ci[i[1]-1:-1:1,:], south)]
94+
for I in r
95+
# @show I, dir(I) ai.∫f[I], ai.∫f[dir(I)]
96+
ai.∫f[I] = ai(ai.x[I],i=dir(I))
97+
end
98+
end
99+
end
100+
101+
function AutomaticIntegration(f, x, x₀; k=3, init=zero(f(x₀)))
102+
Xt = eltype(x)
103+
s = size(x)
104+
Ft = typeof(f(Xt(x₀)))
105+
∫f = zeros(Ft, s)
106+
107+
c,w = gausslegendre(k)
108+
ai = AutomaticIntegration(f, x, x₀, ∫f, c, w)
109+
110+
# We start by integrating from the point on the grid closest to x₀
111+
# to x₀, which is minus the integral value desired, since the
112+
# integral originates at x₀.
113+
i = find_closest(x, x₀)
114+
∫f[i] = init - ai(x₀, i=i)
115+
integrate!(ai, i)
116+
117+
ai
118+
end
119+
120+
(ai::AutomaticIntegration)(x; i=find_closest(ai.x, x)) =
121+
ai.∫f[i] + primitive_integral(ai.f, ai.x[i], x, ai.c, ai.w)
122+
123+
(ai::AutomaticIntegration)(a, b) = ai(b) - ai(a)

test/runtests.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,22 @@ end
113113
display_diagram(system, diagram, expected_momenta, expected_unique, expected_indeterminate)
114114
end
115115
end
116+
117+
@testset "Automatic integration" begin
118+
import StrongFieldApproximation: AutomaticIntegration, ComplexPlane
119+
fine_range(t, η=10) = range(t[1], stop=t[end], length=η*length(t))
120+
121+
tre = range(-1, stop=1, length=201)*4π
122+
tim = range(-1, stop=1, length=101)*2π
123+
t = ComplexPlane(tre, tim)
124+
tfine = ComplexPlane(fine_range(t.re), fine_range(t.im))
125+
@testset "$(f)" for (f,∫f) in [(one,identity), (identity,z->z^2/2),
126+
(z->z^2, z->z^3/3),
127+
(sin, z->1-cos(z))]
128+
@testset "$(name)" for (name,t,tfine) in [("Real line", tre, tfine.re),
129+
("Complex plane", t, tfine)]
130+
ai = AutomaticIntegration(f, t, 0)
131+
@test ai.(tfine) ∫f.(tfine)
132+
end
133+
end
134+
end

0 commit comments

Comments
 (0)