Skip to content
This repository was archived by the owner on Jul 19, 2023. It is now read-only.

Commit 9e3111a

Browse files
authored
Merge pull request #1 from JuliaDiffEq/master
rebase
2 parents 448c401 + 11cee27 commit 9e3111a

18 files changed

+536
-862
lines changed

src/DiffEqOperators.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ include("derivative_operators/BC_operators.jl")
2525

2626
### Derivative Operators
2727
include("derivative_operators/fornberg.jl")
28-
include("derivative_operators/upwind_operator.jl")
29-
include("derivative_operators/derivative_irreg_operator.jl")
3028
include("derivative_operators/derivative_operator.jl")
3129
include("derivative_operators/abstract_operator_functions.jl")
3230
include("derivative_operators/convolutions.jl")
@@ -44,6 +42,7 @@ end
4442

4543
export MatrixFreeOperator
4644
export DiffEqScalar, DiffEqArrayOperator, DiffEqIdentity, JacVecOperator, getops
47-
export AbstractDerivativeOperator, DerivativeOperator, UpwindOperator, FiniteDifference
48-
export RobinBC
45+
export AbstractDerivativeOperator, DerivativeOperator,
46+
CenteredDifference, UpwindDifference
47+
export RobinBC, GeneralBC
4948
end # module

src/derivative_operators/BC_operators.jl

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
abstract type AbstractBC{T} end
1+
abstract type AbstractBC{T} <: AbstractDiffEqLinearOperator{T} end
22

33
"""
44
Robin, General, and in general Neumann and Dirichlet BCs are all affine opeartors, meaning that they take the form Qx = Qax + Qb.
@@ -10,7 +10,7 @@ struct PeriodicBC{T} <: AbstractBC{T}
1010
end
1111

1212
"""
13-
The variables in l are [al, bl, cl], and correspond to a BC of the form al*u(0) + bl*u'(0) = cl
13+
The variables in l are [αl, βl, γl], and correspond to a BC of the form al*u(0) + bl*u'(0) = cl
1414
1515
Implements a robin boundary condition operator Q that acts on a vector to give an extended vector as a result
1616
Referring to (https://github.com/JuliaDiffEq/DiffEqOperators.jl/files/3267835/ghost_node.pdf)
@@ -27,17 +27,17 @@ struct RobinBC{T, V<:AbstractVector{T}} <: AffineBC{T,V}
2727
a_r::V
2828
b_r::T
2929
function RobinBC(l::AbstractArray{T}, r::AbstractArray{T}, dx::AbstractArray{T}, order = one(T)) where {T}
30-
cl, al, bl = l
31-
cr, ar, br = r
30+
αl, βl, γl = l
31+
αr, βr, γr = r
3232
dx_l, dx_r = dx
3333

3434
s = calculate_weights(1, one(T), Array(one(T):convert(T,order+1))) #generate derivative coefficients about the boundary of required approximation order
3535

36-
a_l = -s[2:end]./(1+al*dx_l*s[1]/bl)
37-
a_r = s[end:-1:2]./(1-ar*dx_r*s[1]/br) # for other boundary stencil is flippedlr with *opposite sign*
36+
a_l = -s[2:end]./(αl*dx_l/βl + s[1])
37+
a_r = s[end:-1:2]./(αr*dx_r/βr - s[1]) # for other boundary stencil is flippedlr with *opposite sign*
3838

39-
b_l = cl/(al+bl*s[1]/dx_l)
40-
b_r = cr/(ar-br*s[1]/dx_r)
39+
b_l = γl/(αl+βl*s[1]/dx_l)
40+
b_r = γr/(αr-βr*s[1]/dx_r)
4141

4242
return new{T, typeof(a_l)}(a_l, b_l, a_r, b_r)
4343
end
@@ -86,20 +86,19 @@ struct GeneralBC{T, V<:AbstractVector{T}} <:AffineBC{T,V}
8686
end
8787

8888
#implement Neumann and Dirichlet as special cases of RobinBC
89-
NeumannBC( α::AbstractVector{T}, dx::AbstractVector{T}, order=1) where T = RobinBC([zero(T), one(T), α[1]], [zero(T), one(T), α[2]], dx, order)
90-
DirichletBC::AbstractVector{T}, dx::AbstractVector{T}, order=1) where T = RobinBC([one(T), zero(T), α[1]], [one(T), zero(T), α[2]], dx, order)
91-
89+
NeumannBC::AbstractVector{T}, dx::AbstractVector{T}, order = 1) where T = RobinBC([zero(T), one(T), α[1]], [zero(T), one(T), α[2]], dx, order)
90+
DirichletBC::AbstractVector{T}, dx::AbstractVector{T}, order = 1) where T = RobinBC([one(T), zero(T), α[1]], [one(T), zero(T), α[2]], dx, order)
9291
# other acceptable argument signatures
93-
RobinBC(al::T, bl::T, cl::T, dx_l::T, ar::T, br::T, cr::T, dx_r::T, order = 1) where T = RobinBC([cl,al,bl], [cr, ar, br], [dx_l, dx_r], order)
92+
RobinBC(al::T, bl::T, cl::T, dx_l::T, ar::T, br::T, cr::T, dx_r::T, order = 1) where T = RobinBC([al,bl, cl], [ar, br, cr], [dx_l, dx_r], order)
9493

9594
# this is 'boundary padded vector' as opposed to 'boundary padded array' to distinguish it from the n dimensional implementation that will eventually be neeeded
96-
struct BoundaryPaddedVector{T,T2 <: AbstractVector{T}}
95+
struct BoundaryPaddedVector{T,T2 <: AbstractVector{T}} <: AbstractVector{T}
9796
l::T
9897
r::T
9998
u::T2
10099
end
101100

102-
Base.:*(Q::AffineBC, u) = BoundaryPaddedVector(Q.a_l u[1:length(Q.a_l)] + Q.b_l, Q.a_r u[(end-length(Q.a_r)+1):end] + Q.b_r, u)
101+
Base.:*(Q::AffineBC, u::AbstractVector) = BoundaryPaddedVector(Q.a_l u[1:length(Q.a_l)] + Q.b_l, Q.a_r u[(end-length(Q.a_r)+1):end] + Q.b_r, u)
103102

104103
Base.size(Q::AbstractBC) = (Inf, Inf) #Is this nessecary?
105104
Base.length(Q::BoundaryPaddedVector) = length(Q.u) + 2
@@ -140,4 +139,14 @@ function LinearAlgebra.Array(Q::BoundaryPaddedVector)
140139
return [Q.l; Q.u; Q.r]
141140
end
142141

143-
#TODO: Implement Sparse concretization
142+
function Base.convert(::Type{Array},A::AbstractBC{T}) where T
143+
Array(A)
144+
end
145+
146+
function Base.convert(::Type{SparseMatrixCSC},A::AbstractBC{T}) where T
147+
SparseMatrixCSC(A)
148+
end
149+
150+
function Base.convert(::Type{AbstractMatrix},A::AbstractBC{T}) where T
151+
SparseMatrixCSC(A)
152+
end

src/derivative_operators/abstract_operator_functions.jl

Lines changed: 85 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -17,52 +17,56 @@ checkbounds(A::AbstractDerivativeOperator, k::Colon, j::Integer) =
1717
checkbounds(A::AbstractDerivativeOperator, k::Integer, j::Colon) =
1818
(0 < k size(A, 1) || throw(BoundsError(A, (k,size(A,2)))))
1919

20-
# ~~ getindex ~~
2120
@inline function getindex(A::AbstractDerivativeOperator, i::Int, j::Int)
2221
@boundscheck checkbounds(A, i, j)
23-
mid = div(A.stencil_length, 2) + 1
24-
bpc = A.stencil_length - mid
25-
l = max(1, low(j, mid, bpc))
26-
h = min(A.stencil_length, high(j, mid, bpc, A.stencil_length, A.dimension))
27-
slen = h - l + 1
28-
if abs(i - j) > div(slen, 2)
29-
return 0
22+
bpc = A.boundary_point_count
23+
N = A.len
24+
bsl = A.boundary_stencil_length
25+
slen = A.stencil_length
26+
if bpc > 0 && 1<=i<=bpc
27+
if j > bsl
28+
return 0
29+
else
30+
return A.low_boundary_coefs[i][j]
31+
end
32+
elseif bpc > 0 && (N-bpc)<i<=N
33+
if j < N+2-bsl
34+
return 0
35+
else
36+
return A.high_boundary_coefs[bpc-(N-i)][bsl-(N+2-j)]
37+
end
3038
else
31-
return A.stencil_coefs[mid + j - i]
39+
if j < i-bpc || j > i+slen-bpc-1
40+
return 0
41+
else
42+
return A.stencil_coefs[j-i + 1 + bpc]
43+
end
3244
end
3345
end
3446

3547
# scalar - colon - colon
36-
@inline getindex(A::AbstractDerivativeOperator, kr::Colon, jr::Colon) = convert(Array,A)
48+
@inline getindex(A::AbstractDerivativeOperator, ::Colon, ::Colon) = Array(A)
3749

38-
@inline function getindex(A::AbstractDerivativeOperator, rc::Colon, j)
39-
T = eltype(A.stencil_coefs)
40-
v = zeros(T, A.dimension)
41-
v[j] = one(T)
42-
copyto!(v, A*v)
43-
return v
50+
@inline function getindex(A::AbstractDerivativeOperator, ::Colon, j)
51+
return BandedMatrix(A)[:,j]
4452
end
4553

4654

4755
# symmetric right now
48-
@inline function getindex(A::AbstractDerivativeOperator, i, cc::Colon)
49-
T = eltype(A.stencil_coefs)
50-
v = zeros(T, A.dimension)
51-
v[i] = one(T)
52-
copyto!(v, A*v)
53-
return v
56+
@inline function getindex(A::AbstractDerivativeOperator, i, ::Colon)
57+
return BandedMatrix(A)[i,:]
5458
end
5559

5660

5761
# UnitRanges
58-
@inline function getindex(A::AbstractDerivativeOperator, rng::UnitRange{Int}, cc::Colon)
59-
m = convert(Array,A)
62+
@inline function getindex(A::AbstractDerivativeOperator, rng::UnitRange{Int}, ::Colon)
63+
m = BandedMatrix(A)
6064
return m[rng, cc]
6165
end
6266

6367

64-
@inline function getindex(A::AbstractDerivativeOperator, rc::Colon, rng::UnitRange{Int})
65-
m = convert(Array,A)
68+
@inline function getindex(A::AbstractDerivativeOperator, ::Colon, rng::UnitRange{Int})
69+
m = BandedMatrix(A)
6670
return m[rnd, cc]
6771
end
6872

@@ -79,35 +83,7 @@ end
7983

8084

8185
@inline function getindex(A::AbstractDerivativeOperator{T}, rng::UnitRange{Int}, cng::UnitRange{Int}) where T
82-
N = A.dimension
83-
if (rng[end] - rng[1]) > ((cng[end] - cng[1]))
84-
mat = zeros(T, (N, length(cng)))
85-
v = zeros(T, N)
86-
for i = cng
87-
v[i] = one(T)
88-
#=
89-
calculating the effect on a unit vector to get the matrix of transformation
90-
to get the vector in the new vector space.
91-
=#
92-
mul!(view(mat, :, i - cng[1] + 1), A, v)
93-
v[i] = zero(T)
94-
end
95-
return mat[rng, :]
96-
97-
else
98-
mat = zeros(T, (length(rng), N))
99-
v = zeros(T, N)
100-
for i = rng
101-
v[i] = one(T)
102-
#=
103-
calculating the effect on a unit vector to get the matrix of transformation
104-
to get the vector in the new vector space.
105-
=#
106-
mul!(view(mat, i - rng[1] + 1, :), A, v)
107-
v[i] = zero(T)
108-
end
109-
return mat[:, cng]
110-
end
86+
return BandedMatrix(A)[rng,cng]
11187
end
11288

11389
#=
@@ -126,74 +102,95 @@ function LinearAlgebra.mul!(x_temp::AbstractArray{T,2}, A::AbstractDerivativeOpe
126102
end
127103
end
128104

129-
130105
# Base.length(A::AbstractDerivativeOperator) = A.stencil_length
131106
Base.ndims(A::AbstractDerivativeOperator) = 2
132-
Base.size(A::AbstractDerivativeOperator) = (A.dimension, A.dimension)
107+
Base.size(A::AbstractDerivativeOperator) = (A.len, A.len + 2)
133108
Base.size(A::AbstractDerivativeOperator,i::Integer) = size(A)[i]
134109
Base.length(A::AbstractDerivativeOperator) = reduce(*, size(A))
135110

136-
137111
#=
138112
For the evenly spaced grid we have a symmetric matrix
139113
=#
140-
Base.transpose(A::Union{DerivativeOperator,UpwindOperator}) = A
141-
Base.adjoint(A::Union{DerivativeOperator,UpwindOperator}) = A
142-
LinearAlgebra.issymmetric(::Union{DerivativeOperator,UpwindOperator}) = true
114+
Base.transpose(A::DerivativeOperator) = A
115+
Base.adjoint(A::DerivativeOperator) = A
116+
LinearAlgebra.issymmetric(::DerivativeOperator) = true
143117

144118
#=
145119
Fallback methods that use the full representation of the operator
146120
=#
147-
Base.exp(A::AbstractDerivativeOperator{T}) where T = exp(convert(Array,A))
121+
Base.exp(A::AbstractDerivativeOperator{T}) where T = exp(convert(A))
148122
Base.:\(A::AbstractVecOrMat, B::AbstractDerivativeOperator) = A \ convert(Array,B)
149-
Base.:\(A::AbstractDerivativeOperator, B::AbstractVecOrMat) = convert(Array,A) \ B
123+
Base.:\(A::AbstractDerivativeOperator, B::AbstractVecOrMat) = Array(A) \ B
150124
Base.:/(A::AbstractVecOrMat, B::AbstractDerivativeOperator) = A / convert(Array,B)
151-
Base.:/(A::AbstractDerivativeOperator, B::AbstractVecOrMat) = convert(Array,A) / B
125+
Base.:/(A::AbstractDerivativeOperator, B::AbstractVecOrMat) = Array(A) / B
152126

153-
########################################################################
127+
#=
128+
The Inf opnorm can be calculated easily using the stencil coeffiicents, while other opnorms
129+
default to compute from the full matrix form.
130+
=#
131+
function LinearAlgebra.opnorm(A::DerivativeOperator, p::Real=2)
132+
if p == Inf
133+
sum(abs.(A.stencil_coefs)) / A.dx^A.derivative_order
134+
else
135+
opnorm(BandedMatrix(A), p)
136+
end
137+
end
154138

155-
# Are these necessary?
139+
########################################################################
156140

157141
get_type(::AbstractDerivativeOperator{T}) where {T} = T
158142

159143
function *(A::AbstractDerivativeOperator,x::AbstractVector)
160-
#=
161-
We will output a vector which is a supertype of the types of A and x
162-
to ensure numerical stability
163-
=#
164-
get_type(A) != eltype(x) ? error("DiffEqOperator and array are not of same type!") : nothing
165-
y = zeros(promote_type(eltype(A),eltype(x)), length(x))
144+
y = zeros(promote_type(eltype(A),eltype(x)), length(x)-2)
166145
LinearAlgebra.mul!(y, A::AbstractDerivativeOperator, x::AbstractVector)
167146
return y
168147
end
169148

170149

171150
function *(A::AbstractDerivativeOperator,M::AbstractMatrix)
172-
#=
173-
We will output a vector which is a supertype of the types of A and x
174-
to ensure numerical stability
175-
=#
176-
get_type(A) != eltype(M) ? error("DiffEqOperator and array are not of same type!") : nothing
177-
y = zeros(promote_type(eltype(A),eltype(M)), size(M))
151+
y = zeros(promote_type(eltype(A),eltype(M)), size(A,1), size(M,2))
178152
LinearAlgebra.mul!(y, A::AbstractDerivativeOperator, M::AbstractMatrix)
179153
return y
180154
end
181155

182156

183157
function *(M::AbstractMatrix,A::AbstractDerivativeOperator)
184-
#=
185-
We will output a vector which is a supertype of the types of A and x
186-
to ensure numerical stability
187-
=#
188-
get_type(A) != eltype(M) ? error("DiffEqOperator and array are not of same type!") : nothing
189-
y = zeros(promote_type(eltype(A),eltype(M)), size(M))
190-
LinearAlgebra.mul!(y, A::AbstractDerivativeOperator, M::AbstractMatrix)
158+
y = zeros(promote_type(eltype(A),eltype(M)), size(M,1), size(A,2))
159+
LinearAlgebra.mul!(y, M, BandedMatrix(A))
191160
return y
192161
end
193162

194163

195164
function *(A::AbstractDerivativeOperator,B::AbstractDerivativeOperator)
196-
# TODO: it will result in an operator which calculates
197-
# the derivative of order A.dorder + B.dorder of
198-
# approximation_order = min(approx_A, approx_B)
165+
return BandedMatrix(A)*BandedMatrix(B)
166+
end
167+
168+
################################################################################
169+
170+
function *(coeff_func::Function, A::DerivativeOperator{T,N,Wind}) where {T,N,Wind}
171+
coefficients = A.coefficients === nothing ? Vector{T}(undef,A.len) : A.coefficients
172+
DerivativeOperator{T,N,Wind,typeof(A.dx),typeof(A.stencil_coefs),
173+
typeof(A.low_boundary_coefs),typeof(coefficients),
174+
typeof(coeff_func)}(
175+
A.derivative_order, A.approximation_order,
176+
A.dx, A.len, A.stencil_length,
177+
A.stencil_coefs,
178+
A.boundary_stencil_length,
179+
A.boundary_point_count,
180+
A.low_boundary_coefs,
181+
A.high_boundary_coefs,coefficients,coeff_func
182+
)
199183
end
184+
185+
################################################################################
186+
187+
function DiffEqBase.update_coefficients!(A::AbstractDerivativeOperator,u,p,t)
188+
if A.coeff_func !== nothing
189+
A.coeff_func(A.coefficients,u,p,t)
190+
end
191+
end
192+
193+
################################################################################
194+
195+
(L::DerivativeOperator)(u,p,t) = L*u
196+
(L::DerivativeOperator)(du,u,p,t) = mul!(du,L,u)

0 commit comments

Comments
 (0)