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

Commit aa3ed39

Browse files
authored
Merge pull request #3 from JuliaDiffEq/master
Rebase
2 parents 9e3111a + 7213994 commit aa3ed39

17 files changed

+927
-105
lines changed

CITATION.bib

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@article{DifferentialEquations.jl-2017,
22
author = {Rackauckas, Christopher and Nie, Qing},
33
doi = {10.5334/jors.151},
4-
journal = {},
4+
journal = {The Journal of Open Source Software},
55
keywords = {Applied Mathematics},
66
note = {Exported from https://app.dimensions.ai on 2019/05/05},
77
number = {1},

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1111
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
1212
SuiteSparse = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
1313
BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
14+
NNlib = "872c559c-99b0-510c-b3b7-b6c96a88d5cd"
15+
1416

1517
[compat]
1618
julia = "1"

src/DiffEqOperators.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import Base: +, -, *, /, \, size, getindex, setindex!, Matrix, convert
44
using DiffEqBase, StaticArrays, LinearAlgebra
55
import LinearAlgebra: mul!, ldiv!, lmul!, rmul!, axpy!, opnorm, factorize, I
66
import DiffEqBase: AbstractDiffEqLinearOperator, update_coefficients!, is_constant
7-
using SparseArrays, ForwardDiff, BandedMatrices
7+
using SparseArrays, ForwardDiff, BandedMatrices, NNlib
88

99
abstract type AbstractDerivativeOperator{T} <: AbstractDiffEqLinearOperator{T} end
1010
abstract type AbstractDiffEqCompositeOperator{T} <: AbstractDiffEqLinearOperator{T} end
@@ -29,6 +29,9 @@ include("derivative_operators/derivative_operator.jl")
2929
include("derivative_operators/abstract_operator_functions.jl")
3030
include("derivative_operators/convolutions.jl")
3131
include("derivative_operators/concretization.jl")
32+
include("derivative_operators/ghost_derivative_operator.jl")
33+
include("derivative_operators/derivative_operator_functions.jl")
34+
3235

3336
### Composite Operators
3437
include("composite_operators.jl")
@@ -45,4 +48,5 @@ export DiffEqScalar, DiffEqArrayOperator, DiffEqIdentity, JacVecOperator, getops
4548
export AbstractDerivativeOperator, DerivativeOperator,
4649
CenteredDifference, UpwindDifference
4750
export RobinBC, GeneralBC
51+
export GhostDerivativeOperator
4852
end # module

src/common_defaults.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,24 @@ convert(::Type{AbstractArray}, L::AbstractDiffEqLinearOperator) = convert(Abstra
88
size(L::AbstractDiffEqLinearOperator, args...) = size(convert(AbstractMatrix,L), args...)
99
opnorm(L::AbstractDiffEqLinearOperator, p::Real=2) = opnorm(convert(AbstractMatrix,L), p)
1010
getindex(L::AbstractDiffEqLinearOperator, i::Int) = convert(AbstractMatrix,L)[i]
11-
getindex(L::AbstractDiffEqLinearOperator, I::Vararg{Int, N}) where {N} =
11+
getindex(L::AbstractDiffEqLinearOperator, I::Vararg{Int, N}) where {N} =
1212
convert(AbstractMatrix,L)[I...]
1313
for op in (:*, :/, :\)
14-
@eval $op(L::AbstractDiffEqLinearOperator, x::Union{AbstractVecOrMat,Number}) = $op(convert(AbstractMatrix,L), x)
14+
@eval $op(L::AbstractDiffEqLinearOperator, x::Union{AbstractArray,Number}) = $op(convert(AbstractMatrix,L), x)
1515
@eval $op(x::Union{AbstractVecOrMat,Number}, L::AbstractDiffEqLinearOperator) = $op(x, convert(AbstractMatrix,L))
1616
end
17-
mul!(Y::AbstractVecOrMat, L::AbstractDiffEqLinearOperator, B::AbstractVecOrMat) =
17+
mul!(Y::AbstractArray, L::AbstractDiffEqLinearOperator, B::AbstractArray) =
1818
mul!(Y, convert(AbstractMatrix,L), B)
1919
ldiv!(Y::AbstractVecOrMat, L::AbstractDiffEqLinearOperator, B::AbstractVecOrMat) =
2020
ldiv!(Y, convert(AbstractMatrix,L), B)
2121
for pred in (:isreal, :issymmetric, :ishermitian, :isposdef)
2222
@eval LinearAlgebra.$pred(L::AbstractDiffEqLinearOperator) = $pred(convert(AbstractArray, L))
2323
end
24-
factorize(L::AbstractDiffEqLinearOperator) =
24+
factorize(L::AbstractDiffEqLinearOperator) =
2525
FactorizedDiffEqArrayOperator(factorize(convert(AbstractMatrix, L)))
26-
for fact in (:lu, :lu!, :qr, :qr!, :cholesky, :cholesky!, :ldlt, :ldlt!,
26+
for fact in (:lu, :lu!, :qr, :qr!, :cholesky, :cholesky!, :ldlt, :ldlt!,
2727
:bunchkaufman, :bunchkaufman!, :lq, :lq!, :svd, :svd!)
28-
@eval LinearAlgebra.$fact(L::AbstractDiffEqLinearOperator, args...) =
28+
@eval LinearAlgebra.$fact(L::AbstractDiffEqLinearOperator, args...) =
2929
FactorizedDiffEqArrayOperator($fact(convert(AbstractMatrix, L), args...))
3030
end
3131

src/derivative_operators/abstract_operator_functions.jl

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,32 @@ end
4848
@inline getindex(A::AbstractDerivativeOperator, ::Colon, ::Colon) = Array(A)
4949

5050
@inline function getindex(A::AbstractDerivativeOperator, ::Colon, j)
51-
return BandedMatrix(A)[:,j]
51+
T = eltype(A.stencil_coefs)
52+
v = zeros(T, A.len)
53+
v[j] = one(T)
54+
copyto!(v, A*v)
55+
return v
5256
end
5357

54-
55-
# symmetric right now
5658
@inline function getindex(A::AbstractDerivativeOperator, i, ::Colon)
57-
return BandedMatrix(A)[i,:]
58-
end
59+
@boundscheck checkbounds(A, i, 1)
60+
T = eltype(A.stencil_coefs)
61+
v = zeros(T, A.len+2)
62+
63+
bpc = A.boundary_point_count
64+
N = A.len
65+
bsl = A.boundary_stencil_length
66+
slen = A.stencil_length
5967

68+
if bpc > 0 && 1<=i<=bpc
69+
v[1:bsl] .= A.low_boundary_coefs[i]
70+
elseif bpc > 0 && (N-bpc)<i<=N
71+
v[1:bsl] .= A.high_boundary_coefs[i-(N-1)]
72+
else
73+
v[i-bpc:i-bpc+slen-1] .= A.stencil_coefs
74+
end
75+
return v
76+
end
6077

6178
# UnitRanges
6279
@inline function getindex(A::AbstractDerivativeOperator, rng::UnitRange{Int}, ::Colon)
@@ -86,22 +103,6 @@ end
86103
return BandedMatrix(A)[rng,cng]
87104
end
88105

89-
#=
90-
This definition of the mul! function makes it possible to apply the LinearOperator on
91-
a matrix and not just a vector. It basically transforms the rows one at a time.
92-
=#
93-
function LinearAlgebra.mul!(x_temp::AbstractArray{T,2}, A::AbstractDerivativeOperator{T}, M::AbstractMatrix{T}) where T<:Real
94-
if size(x_temp) == reverse(size(M))
95-
for i = 1:size(M,1)
96-
mul!(view(x_temp,i,:), A, view(M,i,:))
97-
end
98-
else
99-
for i = 1:size(M,2)
100-
mul!(view(x_temp,:,i), A, view(M,:,i))
101-
end
102-
end
103-
end
104-
105106
# Base.length(A::AbstractDerivativeOperator) = A.stencil_length
106107
Base.ndims(A::AbstractDerivativeOperator) = 2
107108
Base.size(A::AbstractDerivativeOperator) = (A.len, A.len + 2)
@@ -140,20 +141,6 @@ end
140141

141142
get_type(::AbstractDerivativeOperator{T}) where {T} = T
142143

143-
function *(A::AbstractDerivativeOperator,x::AbstractVector)
144-
y = zeros(promote_type(eltype(A),eltype(x)), length(x)-2)
145-
LinearAlgebra.mul!(y, A::AbstractDerivativeOperator, x::AbstractVector)
146-
return y
147-
end
148-
149-
150-
function *(A::AbstractDerivativeOperator,M::AbstractMatrix)
151-
y = zeros(promote_type(eltype(A),eltype(M)), size(A,1), size(M,2))
152-
LinearAlgebra.mul!(y, A::AbstractDerivativeOperator, M::AbstractMatrix)
153-
return y
154-
end
155-
156-
157144
function *(M::AbstractMatrix,A::AbstractDerivativeOperator)
158145
y = zeros(promote_type(eltype(A),eltype(M)), size(M,1), size(A,2))
159146
LinearAlgebra.mul!(y, M, BandedMatrix(A))

src/derivative_operators/convolutions.jl

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ function convolve_interior!(x_temp::AbstractVector{T}, _x::BoundaryPaddedVector,
6565
x = _x.u
6666
mid = div(A.stencil_length,2) + 1
6767
# Just do the middle parts
68-
for i in (1+A.boundary_point_count) : (length(x_temp)-A.boundary_point_count)
68+
for i in (2+A.boundary_point_count) : (length(x_temp)-A.boundary_point_count)-1
6969
xtempi = zero(T)
7070
cur_stencil = eltype(stencil) <: AbstractVector ? stencil[i-A.boundary_point_count] : stencil
7171
cur_coeff = typeof(coeff) <: AbstractVector ? coeff[i-A.boundary_point_count] : true
7272
cur_stencil = use_winding(A) && cur_coeff < 0 ? reverse(cur_stencil) : cur_stencil
7373
@inbounds for idx in 1:A.stencil_length
74-
xtempi += cur_coeff * cur_stencil[idx] * x[i - (mid-idx) + 1]
74+
xtempi += cur_coeff * cur_stencil[idx] * x[(i-1) - (mid-idx) + 1]
7575
end
7676
x_temp[i] = xtempi
7777
end
@@ -81,29 +81,55 @@ function convolve_BC_left!(x_temp::AbstractVector{T}, _x::BoundaryPaddedVector,
8181
stencil = A.low_boundary_coefs
8282
coeff = A.coefficients
8383
for i in 1 : A.boundary_point_count
84-
xtempi = stencil[i][1]*_x.l
8584
cur_stencil = stencil[i]
86-
cur_coeff = typeof(coeff) <: AbstractVector ? coeff[i-A.boundary_point_count] : true
85+
cur_coeff = typeof(coeff) <: AbstractVector ? coeff[i] : true
86+
xtempi = cur_coeff*cur_stencil[1]*_x.l
8787
cur_stencil = use_winding(A) && cur_coeff < 0 ? reverse(cur_stencil) : cur_stencil
88-
@inbounds for idx in 2:A.stencil_length
88+
@inbounds for idx in 2:A.boundary_stencil_length
8989
xtempi += cur_coeff * cur_stencil[idx] * _x.u[idx-1]
9090
end
9191
x_temp[i] = xtempi
9292
end
93+
# need to account for x.l in first interior
94+
mid = div(A.stencil_length,2) + 1
95+
x = _x.u
96+
i = 1 + A.boundary_point_count
97+
xtempi = zero(T)
98+
cur_stencil = eltype(A.stencil_coefs) <: AbstractVector ? A.stencil_coefs[i-A.boundary_point_count] : A.stencil_coefs
99+
cur_coeff = typeof(coeff) <: AbstractVector ? coeff[i-A.boundary_point_count] : true
100+
cur_stencil = use_winding(A) && cur_coeff < 0 ? reverse(cur_stencil) : cur_stencil
101+
xtempi = cur_coeff*cur_stencil[1]*_x.l
102+
@inbounds for idx in 2:A.stencil_length
103+
xtempi += cur_coeff * cur_stencil[idx] * x[(i-1) - (mid-idx) + 1]
104+
end
105+
x_temp[i] = xtempi
93106
end
94107

95108
function convolve_BC_right!(x_temp::AbstractVector{T}, _x::BoundaryPaddedVector, A::DerivativeOperator) where {T<:Real}
96-
stencil = A.low_boundary_coefs
109+
stencil = A.high_boundary_coefs
97110
coeff = A.coefficients
98-
bc_start = length(_x.u) - A.stencil_length
111+
bc_start = length(_x.u) - A.boundary_point_count
112+
# need to account for _x.r in last interior convolution
113+
mid = div(A.stencil_length,2) + 1
114+
x = _x.u
115+
i = length(x_temp)-A.boundary_point_count
116+
xtempi = zero(T)
117+
cur_stencil = eltype(A.stencil_coefs) <: AbstractVector ? A.stencil_coefs[i-A.boundary_point_count] : A.stencil_coefs
118+
cur_coeff = typeof(coeff) <: AbstractVector ? coeff[i-A.boundary_point_count] : true
119+
cur_stencil = use_winding(A) && cur_coeff < 0 ? reverse(cur_stencil) : cur_stencil
120+
xtempi = cur_coeff*cur_stencil[end]*_x.r
121+
@inbounds for idx in 1:A.stencil_length-1
122+
xtempi += cur_coeff * cur_stencil[idx] * x[(i-1) - (mid-idx) + 1]
123+
end
124+
x_temp[i] = xtempi
99125
for i in 1 : A.boundary_point_count
100-
xtempi = stencil[i][end]*_x.r
101126
cur_stencil = stencil[i]
102-
cur_coeff = typeof(coeff) <: AbstractVector ? coeff[i-A.boundary_point_count] : true
127+
cur_coeff = typeof(coeff) <: AbstractVector ? coeff[bc_start + i] : true
128+
xtempi = cur_coeff*cur_stencil[end]*_x.r
103129
cur_stencil = use_winding(A) && cur_coeff < 0 ? reverse(cur_stencil) : cur_stencil
104-
@inbounds for idx in A.stencil_length:-1:2
130+
@inbounds for idx in A.stencil_length:-1:1
105131
xtempi += cur_coeff * cur_stencil[end-idx] * _x.u[end-idx+1]
106132
end
107-
x_temp[i] = xtempi
133+
x_temp[bc_start + i] = xtempi
108134
end
109135
end

src/derivative_operators/derivative_operator.jl

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
index(i::Int, N::Int) = i + div(N, 2) + 1
2+
13
struct DerivativeOperator{T<:Real,N,Wind,T2,S1,S2<:SVector,T3,F} <: AbstractDerivativeOperator{T}
24
derivative_order :: Int
35
approximation_order :: Int
@@ -52,14 +54,30 @@ function CenteredDifference{N}(derivative_order::Int,
5254

5355
stencil_length = derivative_order + approximation_order - 1 + (derivative_order+approximation_order)%2
5456
boundary_stencil_length = derivative_order + approximation_order
55-
dummy_x = -div(stencil_length,2) : div(stencil_length,2)
56-
boundary_x = -boundary_stencil_length+1:0
57+
stencil_x = zeros(T, stencil_length)
5758
boundary_point_count = div(stencil_length,2) - 1 # -1 due to the ghost point
59+
60+
interior_x = boundary_point_count+2:len+1-boundary_point_count
61+
dummy_x = -div(stencil_length,2) : div(stencil_length,2)-1
62+
boundary_x = -boundary_stencil_length+1:0
63+
5864
# Because it's a N x (N+2) operator, the last stencil on the sides are the [b,0,x,x,x,x] stencils, not the [0,x,x,x,x,x] stencils, since we're never solving for the derivative at the boundary point.
5965
deriv_spots = (-div(stencil_length,2)+1) : -1
6066
boundary_deriv_spots = boundary_x[2:div(stencil_length,2)]
6167

62-
stencil_coefs = [convert(SVector{stencil_length, T}, calculate_weights(derivative_order, zero(T), dummy_x)) for i in 1:len(dx)]
68+
function generate_coordinates(i, stencil_x, dummy_x, dx)
69+
len = length(stencil_x)
70+
stencil_x .= stencil_x.*zero(T)
71+
for idx in 1:div(len,2)
72+
shifted_idx1 = index(idx, len)
73+
shifted_idx2 = index(-idx, len)
74+
stencil_x[shifted_idx1] = stencil_x[shifted_idx1-1] + dx[i+idx-1]
75+
stencil_x[shifted_idx2] = stencil_x[shifted_idx2+1] - dx[i-idx]
76+
end
77+
return stencil_x
78+
end
79+
80+
stencil_coefs = convert(SVector{length(interior_x)}, [convert(SVector{stencil_length, T}, calculate_weights(derivative_order, zero(T), generate_coordinates(i, stencil_x, dummy_x, dx))) for i in interior_x])
6381
_low_boundary_coefs = SVector{boundary_stencil_length, T}[convert(SVector{boundary_stencil_length, T}, calculate_weights(derivative_order, oneunit(T)*x0, boundary_x)) for x0 in boundary_deriv_spots]
6482
low_boundary_coefs = convert(SVector{boundary_point_count},_low_boundary_coefs)
6583
high_boundary_coefs = convert(SVector{boundary_point_count},reverse(SVector{boundary_stencil_length, T}[reverse(low_boundary_coefs[i]) for i in 1:boundary_point_count]))
@@ -75,7 +93,7 @@ function CenteredDifference{N}(derivative_order::Int,
7593
boundary_stencil_length,
7694
boundary_point_count,
7795
low_boundary_coefs,
78-
high_boundary_coefs,coefficients,coeff_func,false
96+
high_boundary_coefs,coefficients,coeff_func
7997
)
8098
end
8199

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
function LinearAlgebra.mul!(x_temp::AbstractArray{T}, A::DerivativeOperator{T,N}, M::AbstractArray{T}) where {T<:Real,N}
2+
3+
# Check that x_temp has correct dimensions
4+
v = zeros(ndims(x_temp))
5+
v[N] = 2
6+
@assert [size(x_temp)...]+v == [size(M)...]
7+
8+
# Check that axis of differentiation is in the dimensions of M and x_temp
9+
ndimsM = ndims(M)
10+
@assert N <= ndimsM
11+
12+
dimsM = [axes(M)...]
13+
alldims = [1:ndims(M);]
14+
otherdims = setdiff(alldims, N)
15+
16+
idx = Any[first(ind) for ind in axes(M)]
17+
itershape = tuple(dimsM[otherdims]...)
18+
nidx = length(otherdims)
19+
indices = Iterators.drop(CartesianIndices(itershape), 0)
20+
21+
setindex!(idx, :, N)
22+
for I in indices
23+
Base.replace_tuples!(nidx, idx, idx, otherdims, I)
24+
mul!(view(x_temp, idx...), A, view(M, idx...))
25+
end
26+
end
27+
28+
for MT in [2,3]
29+
@eval begin
30+
function LinearAlgebra.mul!(x_temp::AbstractArray{T,$MT}, A::DerivativeOperator{T,N,Wind,T2,S1}, M::AbstractArray{T,$MT}) where {T<:Real,N,Wind,T2,SL,S1<:SArray{Tuple{SL},T,1,SL}}
31+
32+
# Check that x_temp has correct dimensions
33+
v = zeros(ndims(x_temp))
34+
v[N] = 2
35+
@assert [size(x_temp)...]+v == [size(M)...]
36+
37+
# Check that axis of differentiation is in the dimensions of M and x_temp
38+
ndimsM = ndims(M)
39+
@assert N <= ndimsM
40+
41+
# Respahe x_temp for NNlib.conv!
42+
new_size = Any[size(x_temp)...]
43+
bpc = A.boundary_point_count
44+
setindex!(new_size, new_size[N]- 2*bpc, N)
45+
new_shape = []
46+
for i in 1:ndimsM
47+
if i != N
48+
push!(new_shape,:)
49+
else
50+
push!(new_shape,bpc+1:new_size[N]+bpc)
51+
end
52+
end
53+
_x_temp = reshape(view(x_temp, new_shape...), (new_size...,1,1))
54+
55+
# Reshape M for NNlib.conv!
56+
_M = reshape(M, (size(M)...,1,1))
57+
s = A.stencil_coefs
58+
sl = A.stencil_length
59+
60+
# Setup W, the kernel for NNlib.conv!
61+
Wdims = ones(Int64, ndims(_x_temp))
62+
Wdims[N] = sl
63+
W = zeros(Wdims...)
64+
Widx = Any[Wdims...]
65+
setindex!(Widx,:,N)
66+
W[Widx...] = s ./ A.dx^A.derivative_order # this will change later
67+
cv = DenseConvDims(_M, W)
68+
69+
conv!(_x_temp, _M, W, cv)
70+
71+
# Now deal with boundaries
72+
dimsM = [axes(M)...]
73+
alldims = [1:ndims(M);]
74+
otherdims = setdiff(alldims, N)
75+
76+
idx = Any[first(ind) for ind in axes(M)]
77+
itershape = tuple(dimsM[otherdims]...)
78+
nidx = length(otherdims)
79+
indices = Iterators.drop(CartesianIndices(itershape), 0)
80+
81+
setindex!(idx, :, N)
82+
for I in indices
83+
Base.replace_tuples!(nidx, idx, idx, otherdims, I)
84+
convolve_BC_left!(view(x_temp, idx...), view(M, idx...), A)
85+
convolve_BC_right!(view(x_temp, idx...), view(M, idx...), A)
86+
end
87+
end
88+
end
89+
end
90+
91+
function *(A::DerivativeOperator{T,N},M::AbstractArray{T}) where {T<:Real,N}
92+
size_x_temp = [size(M)...]
93+
size_x_temp[N] -= 2
94+
x_temp = zeros(promote_type(eltype(A),eltype(M)), size_x_temp...)
95+
LinearAlgebra.mul!(x_temp, A, M)
96+
return x_temp
97+
end

0 commit comments

Comments
 (0)