Skip to content

Commit ced61b3

Browse files
authored
Demonstrate the use of SymmetricEigensystem in examples (#881)
* Update eigen examples * remove eigs * Eigenfunctions in example * Add comments * remove checks in readmetests if there are no actual tests * revert removing tests * rename tunneling file * fix filename * make functions multiline * separate function for interlace
1 parent 353d102 commit ced61b3

File tree

8 files changed

+159
-94
lines changed

8 files changed

+159
-94
lines changed

docs/make.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ end
3333
makedocs(
3434
format = Documenter.HTML(),
3535
sitename = "ApproxFun.jl",
36-
authors = "Sheehan Olver, Jishnu Bhattacharya and contributors",
36+
authors = "Sheehan Olver, Mikael Slevinsky, Jishnu Bhattacharya and contributors",
3737
pages = Any[
3838
"Home" => "index.md",
3939
"Usage" => Any[

examples/Eigenvalue.jl

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,33 @@ p
1616
# If the solutions are not relatively constant near the boundary then one should push
1717
# the boundaries further out.
1818

19-
include("Eigenvalue_tunnelling.jl")
20-
21-
# We plot the first few eigenfunctions
22-
p = Plots.plot(V, legend=false)
23-
Plots.vline!([-Lx/2, Lx/2], linecolor=:black)
24-
p_twin = Plots.twinx(p)
25-
for k=1:6
26-
Plots.plot!(p_twin, real(v[k]/norm(v[k]) + λ[k]), label="$k")
27-
end
28-
p
29-
30-
# Note that the parity symmetry isn't preserved exactly at finite matrix sizes.
31-
# In general, it's better to preserve the symmetry of the operator matrices (see section below),
32-
# and projecting them on to the appropriate subspaces.
33-
3419
# For problems with different contraints or boundary conditions,
3520
# `B` can be any zero functional constraint, e.g., `DefiniteIntegral()`.
3621

37-
include("Eigenvalue_symmetric.jl")
22+
include("Eigenvalue_anharmonic.jl")
3823

3924
# We plot the eigenvalues
4025
import Plots
41-
Plots.plot(λ; title = "Eigenvalues", legend=false)
26+
Plots.plot(λ, title = "Eigenvalues", legend=false)
27+
28+
include("Eigenvalue_well_barrier.jl")
29+
30+
# We plot the first few eigenfunctions offset by their eigenvalues.
31+
# The eigenfunctions appear in odd-even pairs as expected.
32+
33+
import Plots
34+
using LinearAlgebra: norm
35+
p1 = Plots.plot(Vfull, legend=false, ylim=(-Inf, λ[14]), title="Eigenfunctions",
36+
seriestype=:path, linestyle=:dash, linewidth=2)
37+
Plots.vline!([-Lx/2, Lx/2], color=:black)
38+
for k=1:12
39+
Plots.plot!(real(v[k]/norm(v[k]) + λ[k]))
40+
end
41+
42+
# Zoom into the ground state:
43+
p2 = Plots.plot(Vfull, legend=false, ylim=(-Inf, λ[3]), title="Ground state",
44+
seriestype=:path, linestyle=:dash, linewidth=2)
45+
Plots.vline!([-Lx/2, Lx/2], color=:black)
46+
Plots.plot!(real(v[1]/norm(v[1]) + λ[1]), linewidth=2)
47+
48+
Plots.plot(p1, p2, layout = 2)

examples/Eigenvalue_anharmonic.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# ## Self-adjoint Eigenvalue Problem
2+
# Ref:
3+
# [J. L. Aurentz & R. M. Slevinsky (2019), arXiv:1903.08538](https://arxiv.org/abs/1903.08538)
4+
5+
# We solve the confined anharmonic oscillator
6+
# ```math
7+
# \left[-\frac{d^2}{dx^2} + V(x)\right] u = λu,
8+
# ```
9+
# where ``u(\pm 10) = 0``, ``V(x) = ωx^2 + x^4``, and ``ω = 25``.
10+
11+
using ApproxFun
12+
using LinearAlgebra
13+
using BandedMatrices
14+
15+
# Define parameters
16+
ω = 25.0
17+
d = -10..10;
18+
S = Legendre(d); # Equivalently, Ultraspherical(0.5, d)
19+
20+
# Construct the differential operator
21+
V = Fun(x -> ω * x^2 + x^4, S)
22+
L = -Derivative(S, 2) + V;
23+
24+
# Boundary conditions that are used in the basis recombination
25+
B = Dirichlet(S);
26+
27+
# The system may be recast as a generalized eigenvalue problem
28+
# ``A_S\,v = λ\, B_S\, v``, where ``A_S`` and ``B_S`` are symmetric band matrices.
29+
# We wrap the operators in `SymmetricEigensystem` to implicitly perform the basis recombination
30+
31+
SEg = ApproxFun.SymmetricEigensystem(L, B);
32+
33+
# We construct `n × n` matrix representations of the opertors that we diagonalize
34+
n = 3000
35+
λ = eigvals(SEg, n);
36+
37+
# We retain a fraction of the eigenvalues with the least magnitude
38+
λ = λ[1:round(Int, 3n/5)];

examples/Eigenvalue_standard.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# where ``λ_i`` is the ``i^{th}`` eigenvalue of the ``L`` and has a corresponding
1010
# *eigenfunction* ``\mathop{u}_i(x)``.
1111

12-
### Quantum harmonic oscillator
12+
# ### Quantum harmonic oscillator
1313

1414
# A classic eigenvalue problem is known as the quantum harmonic oscillator where
1515
# ```math

examples/Eigenvalue_symmetric.jl

Lines changed: 0 additions & 45 deletions
This file was deleted.

examples/Eigenvalue_tunnelling.jl

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# ### Infinite well with a barrier
2+
3+
# We solve the Schrodinger equation in an infinite square well in the domain `-Lx/2..Lx/2`, with a finite barrier in the middle from `-d/2..d/2`
4+
# ```math
5+
# \mathop{L} = -\frac{1}{2}\frac{\mathop{d}^2}{\mathop{dx}^2} + V(x),
6+
# ```
7+
# where ``V(x)`` is given by an infinite well with a smoothed barrier at the center.
8+
9+
# We note that the system has parity symmetry, so the solutions may be separated into odd and even functions.
10+
# We may therefore solve the problem only for half the domain, with Dirichlet boundary conditions at the midpoint
11+
# for odd functions, and Neumann conditions for even functions.
12+
# This projection to subspaces allows us to halve the sizes of matrices that we need to diagonalize
13+
14+
Lx = 4 # size of the domain
15+
S = Legendre(0..Lx/2)
16+
x = Fun(S)
17+
d = 1 # size of the barrier
18+
Δ = 0.1 # smoothing scale of the barrier
19+
V = 50 * (1 - tanh((x - d/2)/Δ))/2; # right half of the potential barrier
20+
H = -Derivative(S)^2/2 + V;
21+
22+
# Odd solutions, with a zero Dirichlet condition at `0` representing a node
23+
B = Dirichlet(S);
24+
Seig = ApproxFun.SymmetricEigensystem(H, B);
25+
26+
# Diagonalize `n × n` matrix representations of the basis-recombined operators
27+
# We specify a tolerance to reject spurious solutions arising from the discretization
28+
n = 100
29+
λodd, vodd = ApproxFun.eigs(Seig, n, tolerance=1e-8);
30+
31+
# To extend the solutions to the full domain, we construct the left-half space.
32+
Scomplement = Legendre(-Lx/2..0);
33+
34+
# We use the fact that Legendre polynomials of odd orders are odd functions,
35+
# and those of even orders are even functions
36+
# Using this, for the odd solutions, we negate the even-order coefficients to construct the odd image in `-Lx/2..0`
37+
function oddimage(f, Scomplement)
38+
coeffs = [(-1)^isodd(m) * c for (m,c) in enumerate(coefficients(f))]
39+
Fun(Scomplement, coeffs)
40+
end;
41+
voddimage = oddimage.(vodd, Scomplement);
42+
43+
# Construct the functions over the entire domain `-Lx/2..Lx/2` as piecewise sums over the two half domains `-Lx/2..0` and `0..Lx/2`
44+
voddfull = voddimage .+ vodd;
45+
46+
# Even solutions, with a Neumann condition at `0` representing the symmetry of the function
47+
B = [lneumann(S); rdirichlet(S)];
48+
49+
Seig = ApproxFun.SymmetricEigensystem(H, B);
50+
λeven, veven = ApproxFun.eigs(Seig, n, tolerance=1e-8);
51+
52+
# For the even solutions, we negate the odd-order coefficients to construct the even image in `-Lx/2..0`
53+
function evenimage(f, Scomplement)
54+
coeffs = [(-1)^iseven(m) * c for (m,c) in enumerate(coefficients(f))]
55+
Fun(Scomplement, coeffs)
56+
end;
57+
vevenimage = evenimage.(veven, Scomplement);
58+
vevenfull = vevenimage .+ veven;
59+
60+
# We interlace the eigenvalues and eigenvectors to obtain the entire spectrum
61+
function interlace(a::AbstractVector, b::AbstractVector)
62+
vec(permutedims([a b]))
63+
end;
64+
λ = interlace(λeven, λodd);
65+
v = interlace(vevenfull, voddfull);
66+
67+
# Symmetrize the potential using an even image (this is mainly for plotting/post-processing)
68+
Vevenimage = evenimage(V, Scomplement);
69+
Vfull = Vevenimage + V;

test/ReadmeTest.jl

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ const EXAMPLES_DIR = joinpath(dirname(dirname(pathof(ApproxFun))), "examples")
99

1010
include(joinpath(@__DIR__, "testutils.jl"))
1111

12+
function get_included_files(filename)
13+
v = [l for l in eachline(joinpath(EXAMPLES_DIR, filename)) if contains(l, "include")]
14+
strip.(getindex.(split.(getindex.(split.(v, "include("), 2), ")"), 1), '\"')
15+
end
16+
1217
@verbose @testset "Readme" begin
1318
@testset "Calculus and algebra" begin
1419
x = Fun(identity,0..10)
@@ -58,34 +63,44 @@ include(joinpath(@__DIR__, "testutils.jl"))
5863
end
5964

6065
@testset "NonlinearBVP" begin
61-
include(joinpath(EXAMPLES_DIR, "NonlinearBVP1.jl"))
62-
include(joinpath(EXAMPLES_DIR, "NonlinearBVP2.jl"))
66+
for f in get_included_files("NonlinearBVP.jl")
67+
include(joinpath(EXAMPLES_DIR, f))
68+
end
6369
end
6470

6571
@testset "ODE" begin
66-
include(joinpath(EXAMPLES_DIR, "ODE_BVP.jl"))
67-
include(joinpath(EXAMPLES_DIR, "ODE_increaseprec.jl"))
72+
for f in get_included_files("ODE.jl")
73+
include(joinpath(EXAMPLES_DIR, f))
74+
end
6875
end
6976
@testset "System of Equations" begin
70-
include(joinpath(EXAMPLES_DIR, "System1.jl"))
77+
for f in get_included_files("system_of_eqn.jl")
78+
include(joinpath(EXAMPLES_DIR, f))
79+
end
7180
end
7281

7382
@testset "Periodic" begin
74-
include(joinpath(EXAMPLES_DIR, "Periodic1.jl"))
83+
for f in get_included_files("Periodic.jl")
84+
include(joinpath(EXAMPLES_DIR, f))
85+
end
7586
end
7687
@testset "Sampling" begin
77-
include(joinpath(EXAMPLES_DIR, "Sampling1.jl"))
88+
for f in get_included_files("Sampling.jl")
89+
include(joinpath(EXAMPLES_DIR, f))
90+
end
7891
end
7992
@testset "Eigenvalue" begin
80-
include(joinpath(EXAMPLES_DIR, "Eigenvalue_standard.jl"))
81-
include(joinpath(EXAMPLES_DIR, "Eigenvalue_symmetric.jl"))
93+
for f in get_included_files("Eigenvalue.jl")
94+
include(joinpath(EXAMPLES_DIR, f))
95+
end
8296
end
8397

8498
# this is broken on v1.6 (on BandedArrays < v0.16.16), so we only test on higher versions
8599
if VERSION >= v"1.7"
86100
@testset "PDE" begin
87-
include(joinpath(EXAMPLES_DIR, "PDE_Poisson.jl"))
88-
include(joinpath(EXAMPLES_DIR, "PDE_Helmholtz.jl"))
101+
for f in get_included_files("PDE.jl")
102+
include(joinpath(EXAMPLES_DIR, f))
103+
end
89104
end
90105
end
91106

0 commit comments

Comments
 (0)