Skip to content

Commit bf52548

Browse files
authored
Support Neumann conditions in p-FEM (#75)
* Support Neumann conditions in p-FEM * Update test_odes.jl * natural (Neumann) boundary conditions work! * cos.(θ) .* F * improve OP ldiv special cases * Update test_odes.jl * one-sided Neumann test * LazyArrays v0.22 * Update test_odes.jl * Update Project.toml * improve cov * Update test_legendre.jl
1 parent 771cf31 commit bf52548

File tree

10 files changed

+255
-129
lines changed

10 files changed

+255
-129
lines changed

Project.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ClassicalOrthogonalPolynomials"
22
uuid = "b30e2e7b-c4ee-47da-9d5f-2c5c27239acd"
33
authors = ["Sheehan Olver <[email protected]>"]
4-
version = "0.4.9"
4+
version = "0.4.10"
55

66
[deps]
77
ArrayLayouts = "4c555306-a7a7-4459-81d9-ec55ddd5c99a"
@@ -22,6 +22,7 @@ LazyArrays = "5078a376-72f3-5289-bfd5-ec5146d43c02"
2222
LazyBandedMatrices = "d7e5e226-e90b-4449-9968-0f923699bf6f"
2323
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2424
QuasiArrays = "c4ea9172-b204-11e9-377d-29865faadc5c"
25+
SemiseparableMatrices = "f8ebbe35-cbfb-4060-bf7f-b10e4670cf57"
2526
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
2627

2728
[compat]
@@ -34,14 +35,14 @@ DomainSets = "0.5.6"
3435
FFTW = "1.1"
3536
FastGaussQuadrature = "0.4.3"
3637
FastTransforms = "0.12"
37-
FillArrays = "0.11, 0.12"
38+
FillArrays = "0.12"
3839
HypergeometricFunctions = "0.3.4"
3940
InfiniteArrays = "0.12"
4041
InfiniteLinearAlgebra = "0.6"
4142
IntervalSets = "0.5"
42-
LazyArrays = "0.21.20"
43+
LazyArrays = "0.22"
4344
LazyBandedMatrices = "0.7"
44-
QuasiArrays = "0.7, 0.8"
45+
QuasiArrays = "0.8"
4546
SpecialFunctions = "1.0"
4647
julia = "1.6"
4748

src/ClassicalOrthogonalPolynomials.jl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ import QuasiArrays: cardinality, checkindex, QuasiAdjoint, QuasiTranspose, Inclu
2828
QuasiDiagonal, MulQuasiArray, MulQuasiMatrix, MulQuasiVector, QuasiMatMulMat,
2929
ApplyQuasiArray, ApplyQuasiMatrix, LazyQuasiArrayApplyStyle, AbstractQuasiArrayApplyStyle,
3030
LazyQuasiArray, LazyQuasiVector, LazyQuasiMatrix, LazyLayout, LazyQuasiArrayStyle,
31-
_getindex, layout_getindex, _factorize, AbstractQuasiArray, AbstractQuasiMatrix, AbstractQuasiVector
31+
_getindex, layout_getindex, _factorize, AbstractQuasiArray, AbstractQuasiMatrix, AbstractQuasiVector,
32+
AbstractQuasiFill, _dot
3233

3334
import InfiniteArrays: OneToInf, InfAxes, Infinity, AbstractInfUnitRange, InfiniteCardinal, InfRanges
3435
import InfiniteLinearAlgebra: chop!, chop
@@ -351,6 +352,21 @@ function \(wA::WeightedOrthogonalPolynomial, wB::WeightedOrthogonalPolynomial)
351352
A \ ((A * (wA \ w_B)) .* B)
352353
end
353354

355+
## special expansion routines for constants and x
356+
function _op_ldiv(P::AbstractQuasiMatrix{V}, f::AbstractQuasiFill{T,1}) where {T,V}
357+
TV = promote_type(T,V)
358+
Vcat(getindex_value(f)/_p0(P),Zeros{TV}(∞))
359+
end
360+
361+
_op_ldiv(::AbstractQuasiMatrix{V}, ::QuasiZeros{T,1}) where {T,V} = Zeros{promote_type(T,V)}(∞)
362+
363+
function _op_ldiv(P::AbstractQuasiMatrix{V}, f::Inclusion{T}) where {T,V}
364+
axes(P,1) == f || throw(DimensionMismatch())
365+
A,B,_ = recurrencecoefficients(P)
366+
TV = promote_type(T,V)
367+
c = inv(convert(TV,A[1]*_p0(P)))
368+
Vcat(-B[1]c, c, Zeros{TV}(∞))
369+
end
354370

355371
include("classical/hermite.jl")
356372
include("classical/jacobi.jl")

src/classical/fourier.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,8 @@ function broadcasted(::LazyQuasiArrayStyle{2}, ::typeof(*), s::BroadcastQuasiVec
7979
Vcat([zeros(T,1,1)], Fill(Matrix(zero(T)*I,2,2),∞)),
8080
Vcat([[one(T)/2 0]], Fill([0 -one(T)/2; one(T)/2 0],∞))))
8181
end
82+
83+
84+
# support cos.(θ) .* F
85+
Base.broadcasted(::LazyQuasiArrayStyle{2}, ::typeof(*), c::Broadcasted{<:Any,<:Any,typeof(cos),<:Tuple{<:Inclusion{<:Any,RealNumbers}}}, F::Fourier) = materialize(c) .* F
86+
Base.broadcasted(::LazyQuasiArrayStyle{2}, ::typeof(*), c::Broadcasted{<:Any,<:Any,typeof(sin),<:Tuple{<:Inclusion{<:Any,RealNumbers}}}, F::Fourier) = materialize(c) .* F

src/classical/jacobi.jl

Lines changed: 6 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -33,49 +33,16 @@ summary(io::IO, w::JacobiWeight) = print(io, "(1-x)^$(w.a) * (1+x)^$(w.b) on -1.
3333

3434
sum(P::JacobiWeight) = jacobimoment(P.a, P.b)
3535

36-
struct LegendreWeight{T} <: AbstractJacobiWeight{T} end
37-
LegendreWeight() = LegendreWeight{Float64}()
38-
legendreweight(d::AbstractInterval{T}) where T = LegendreWeight{float(T)}()[affine(d,ChebyshevInterval{T}())]
39-
40-
function getindex(w::LegendreWeight{T}, x::Number) where T
41-
x axes(w,1) || throw(BoundsError())
42-
one(T)
43-
end
44-
45-
getproperty(w::LegendreWeight{T}, ::Symbol) where T = zero(T)
46-
47-
sum(::LegendreWeight{T}) where T = 2one(T)
48-
49-
_weighted(::LegendreWeight, P) = P
50-
_weighted(::SubQuasiArray{<:Any,1,<:LegendreWeight}, P) = P
51-
52-
broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(*), ::LegendreWeight{T}, ::LegendreWeight{V}) where {T,V} =
53-
LegendreWeight{promote_type(T,V)}()
54-
55-
broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(sqrt), w::LegendreWeight{T}) where T = w
56-
57-
broadcasted(::LazyQuasiArrayStyle{1}, ::typeof(Base.literal_pow), ::Base.RefValue{typeof(^)}, w::LegendreWeight, ::Base.RefValue{Val{k}}) where k = w
5836

5937
# support auto-basis determination
6038

6139
singularities(a::AbstractAffineQuasiVector) = singularities(a.x)
62-
singularitiesbroadcast(_, L::LegendreWeight) = L # Assume we stay smooth
63-
singularitiesbroadcast(::typeof(exp), L::LegendreWeight) = L
64-
singularitiesbroadcast(::typeof(Base.literal_pow), ::typeof(^), L::LegendreWeight, ::Val) = L
6540

6641

6742
for op in (:+, :*)
6843
@eval singularitiesbroadcast(::typeof($op), A, B, C, D...) = singularitiesbroadcast(*, singularitiesbroadcast(*, A, B), C, D...)
6944
end
70-
for op in (:+, :-, :*)
71-
@eval begin
72-
singularitiesbroadcast(::typeof($op), A::LegendreWeight, B::LegendreWeight) = LegendreWeight{promote_type(eltype(A), eltype(B))}()
73-
singularitiesbroadcast(::typeof($op), L::LegendreWeight, ::NoSingularities) = L
74-
singularitiesbroadcast(::typeof($op), ::NoSingularities, L::LegendreWeight) = L
75-
end
76-
end
77-
singularitiesbroadcast(::typeof(^), L::LegendreWeight, ::NoSingularities) = L
78-
singularitiesbroadcast(::typeof(/), ::NoSingularities, L::LegendreWeight) = L # can't find roots
45+
7946

8047
_parent(::NoSingularities) = NoSingularities()
8148
_parent(a) = parent(a)
@@ -87,38 +54,13 @@ singularitiesbroadcast(F, V::Union{NoSingularities,SubQuasiArray}...) = singular
8754
singularitiesbroadcast(::typeof(*), V::Union{NoSingularities,SubQuasiArray}...) = singularitiesbroadcast(*, map(_parent,V)...)[_parentindices(V...)...]
8855

8956

90-
singularitiesbroadcast(::typeof(*), ::LegendreWeight, b::AbstractJacobiWeight) = b
91-
singularitiesbroadcast(::typeof(*), a::AbstractJacobiWeight, ::LegendreWeight) = a
92-
9357
abstract type AbstractJacobi{T} <: OrthogonalPolynomial{T} end
9458

95-
singularities(::AbstractJacobi{T}) where T = LegendreWeight{T}()
96-
singularities(::Inclusion{T,<:AbstractInterval}) where T = LegendreWeight{T}()
97-
singularities(d::Inclusion{T,<:Interval}) where T = LegendreWeight{T}()[affine(d,ChebyshevInterval{T}())]
98-
99-
struct Legendre{T} <: AbstractJacobi{T} end
100-
Legendre() = Legendre{Float64}()
101-
102-
legendre() = Legendre()
103-
legendre(d::AbstractInterval{T}) where T = Legendre{float(T)}()[affine(d,ChebyshevInterval{T}()), :]
104-
105-
"""
106-
legendrep(n, z)
107-
108-
computes the `n`-th Legendre polynomial at `z`.
109-
"""
110-
legendrep(n::Integer, z::Number) = Base.unsafe_getindex(Legendre{typeof(z)}(), z, n+1)
59+
include("legendre.jl")
11160

61+
singularitiesbroadcast(::typeof(*), ::LegendreWeight, b::AbstractJacobiWeight) = b
62+
singularitiesbroadcast(::typeof(*), a::AbstractJacobiWeight, ::LegendreWeight) = a
11263

113-
==(::Legendre, ::Legendre) = true
114-
115-
OrthogonalPolynomial(w::LegendreWeight{T}) where {T} = Legendre{T}()
116-
orthogonalityweight(::Legendre{T}) where T = LegendreWeight{T}()
117-
118-
function qr(P::Legendre)
119-
Q = Normalized(P)
120-
QuasiQR(Q, Diagonal(Q.scaling))
121-
end
12264

12365
struct Jacobi{T} <: AbstractJacobi{T}
12466
a::T
@@ -221,12 +163,8 @@ function plotgrid(Pn::SubQuasiArray{T,2,<:AbstractJacobi,<:Tuple{Inclusion,Any}}
221163
ChebyshevGrid{2,T}(40maximum(jr))
222164
end
223165

224-
225-
function ldiv(::Legendre{V}, f::AbstractQuasiVector) where V
226-
T = ChebyshevT{V}()
227-
[cheb2leg(paddeddata(T \ f)); zeros(V,∞)]
228-
end
229-
166+
ldiv(P::Jacobi{V}, f::Inclusion{T}) where {T,V} = _op_ldiv(P, f)
167+
ldiv(P::Jacobi{V}, f::AbstractQuasiFill{T,1}) where {T,V} = _op_ldiv(P, f)
230168
function ldiv(P::Jacobi{V}, f::AbstractQuasiVector) where V
231169
T = ChebyshevT{V}()
232170
[cheb2jac(paddeddata(T \ f), P.a, P.b); zeros(V,∞)]
@@ -237,23 +175,7 @@ end
237175
# Mass Matrix
238176
#########
239177

240-
# massmatrix(P) = Weighted(P)'P
241-
massmatrix(P::Legendre{T}) where T = Diagonal(convert(T,2) ./ (2(0:∞) .+ 1))
242-
243-
244-
245-
"""
246-
legendre_massmatrix
247-
248-
computes the massmatrix by first re-expanding in Legendre
249-
"""
250-
function legendre_massmatrix(Ac, B)
251-
A = parent(Ac)
252-
P = Legendre{eltype(B)}()
253-
(P\A)'*massmatrix(P)*(P\B)
254-
end
255178

256-
@simplify *(Ac::QuasiAdjoint{<:Any,<:Legendre}, B::Legendre) = massmatrix(Legendre{promote_type(eltype(Ac), eltype(B))}())
257179
@simplify *(Ac::QuasiAdjoint{<:Any,<:AbstractJacobi}, B::AbstractJacobi) = legendre_massmatrix(Ac,B)
258180
@simplify *(Ac::QuasiAdjoint{<:Any,<:AbstractJacobi}, B::Weighted{<:Any,<:AbstractJacobi}) = legendre_massmatrix(Ac,B)
259181

@@ -287,14 +209,6 @@ end
287209
# Jacobi Matrix
288210
########
289211

290-
jacobimatrix(::Legendre{T}) where T = Tridiagonal((one(T):∞)./(1:2:∞), Zeros{T}(∞), (one(T):∞)./(3:2:∞))
291-
292-
# These return vectors A[k], B[k], C[k] are from DLMF. Cause of MikaelSlevinsky we need an extra entry in C ... for now.
293-
function recurrencecoefficients(::Legendre{T}) where T
294-
n = zero(T):
295-
((2n .+ 1) ./ (n .+ 1), Zeros{T}(∞), n ./ (n .+ 1))
296-
end
297-
298212
function jacobimatrix(J::Jacobi)
299213
b,a = J.b,J.a
300214
n = 0:
@@ -316,19 +230,6 @@ function recurrencecoefficients(P::Jacobi)
316230
(A,B,C)
317231
end
318232

319-
# explicit special case for normalized Legendre
320-
# todo: do we want these explicit constructors for normalized Legendre?
321-
# function jacobimatrix(::Normalized{<:Any,<:Legendre{T}}) where T
322-
# b = (one(T):∞) ./sqrt.(4 .*(one(T):∞).^2 .-1)
323-
# Symmetric(_BandedMatrix(Vcat(zeros(∞)', (b)'), ∞, 1, 0), :L)
324-
# end
325-
# function recurrencecoefficients(::Normalized{<:Any,<:Legendre{T}}) where T
326-
# n = zero(T):∞
327-
# nn = one(T):∞
328-
# ((2n .+ 1) ./ (n .+ 1) ./ sqrt.(1 .-2 ./(3 .+2n)), Zeros{T}(∞), Vcat(zero(T),nn ./ (nn .+ 1) ./ sqrt.(1 .-4 ./(3 .+2nn))))
329-
# end
330-
331-
@simplify *(X::Identity, P::Legendre) = ApplyQuasiMatrix(*, P, P\(X*P))
332233

333234

334235

@@ -519,25 +420,11 @@ end
519420
end
520421

521422

522-
###
523-
# Splines
524-
###
525-
526-
function \(A::Legendre, B::HeavisideSpline)
527-
@assert B.points == -1:2:1
528-
Vcat(1, Zeros(∞,1))
529-
end
530423

531424
###
532425
# sum
533426
###
534427

535-
function _sum(P::Legendre{T}, dims) where T
536-
@assert dims == 1
537-
Hcat(convert(T, 2), Zeros{T}(1,∞))
538-
end
539-
540-
_sum(p::SubQuasiArray{T,1,Legendre{T},<:Tuple{Inclusion,Int}}, ::Colon) where T = parentindices(p)[2] == 1 ? convert(T, 2) : zero(T)
541428
_sum(P::AbstractJacobi{T}, dims) where T = 2 * (Legendre{T}() \ P)[1:1,:]
542429

543430

0 commit comments

Comments
 (0)