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

Commit fb9e717

Browse files
Merge pull request #279 from grahamas/local-rebased
Multidimensional handling for GhostDerivativeOperators (part 3)
2 parents 1294911 + d21a60d commit fb9e717

15 files changed

Lines changed: 558 additions & 228 deletions

src/DiffEqOperators.jl

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import DiffEqBase: AbstractDiffEqLinearOperator, update_coefficients!, isconstan
77
using SparseArrays, ForwardDiff, BandedMatrices, NNlib, LazyArrays, BlockBandedMatrices
88
using LazyBandedMatrices, ModelingToolkit
99

10+
abstract type AbstractDiffEqAffineOperator{T} end
1011
abstract type AbstractDerivativeOperator{T} <: AbstractDiffEqLinearOperator{T} end
1112
abstract type AbstractDiffEqCompositeOperator{T} <: AbstractDiffEqLinearOperator{T} end
1213
abstract type AbstractMatrixFreeOperator{T} <: AbstractDiffEqLinearOperator{T} end
@@ -22,15 +23,14 @@ include("utils.jl")
2223
include("boundary_padded_arrays.jl")
2324

2425
### Boundary Operators
25-
include("derivative_operators/BC_operators.jl")
26+
include("derivative_operators/bc_operators.jl")
2627
include("derivative_operators/multi_dim_bc_operators.jl")
2728

2829
### Derivative Operators
2930
include("derivative_operators/fornberg.jl")
3031
include("derivative_operators/derivative_operator.jl")
3132
include("derivative_operators/abstract_operator_functions.jl")
3233
include("derivative_operators/convolutions.jl")
33-
include("derivative_operators/concretization.jl")
3434
include("derivative_operators/ghost_derivative_operator.jl")
3535
include("derivative_operators/derivative_operator_functions.jl")
3636
include("derivative_operators/coefficient_functions.jl")
@@ -42,8 +42,11 @@ include("MOL_discretization.jl")
4242

4343
include("docstrings.jl")
4444

45+
### Concretizations
46+
include("derivative_operators/concretization.jl")
47+
4548
# The (u,p,t) and (du,u,p,t) interface
46-
for T in [DiffEqScaledOperator, DiffEqOperatorCombination, DiffEqOperatorComposition]
49+
for T in [DiffEqScaledOperator, DiffEqOperatorCombination, DiffEqOperatorComposition, GhostDerivativeOperator]
4750
(L::T)(u,p,t) = (update_coefficients!(L,u,p,t); L * u)
4851
(L::T)(du,u,p,t) = (update_coefficients!(L,u,p,t); mul!(du,L,u))
4952
end
@@ -53,8 +56,9 @@ export AnalyticalJacVecOperator, JacVecOperator, getops
5356
export AbstractDerivativeOperator, DerivativeOperator,
5457
CenteredDifference, UpwindDifference
5558
export DirichletBC, Dirichlet0BC, NeumannBC, Neumann0BC, RobinBC, GeneralBC, MultiDimBC, PeriodicBC,
56-
MultiDimDirectionalBC, ComposedMultiDimBC,
57-
compose, decompose, perpsize
59+
MultiDimDirectionalBC, ComposedMultiDimBC
60+
export compose, decompose, perpsize
61+
5862
export GhostDerivativeOperator
5963
export MOLFiniteDifference
6064
end # module

src/boundary_padded_arrays.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ end
1818

1919
Base.length(Q::BoundaryPaddedVector) = length(Q.u) + 2
2020
Base.size(Q::BoundaryPaddedVector) = (length(Q.u) + 2,)
21+
unpadded_size(Q::BoundaryPaddedVector) = size(Q.u)
22+
unpadded_size(Q::AbstractArray) = size(Q)
2123
Base.lastindex(Q::BoundaryPaddedVector) = Base.length(Q)
2224

2325
function Base.getindex(Q::BoundaryPaddedVector,i)
@@ -47,6 +49,7 @@ function Base.size(Q::BoundaryPaddedArray)
4749
S[getaxis(Q)] += 2
4850
return Tuple(S)
4951
end
52+
unpadded_size(Q::BoundaryPaddedArray) = size(Q.u)
5053

5154
"""
5255
A = compose(padded_arrays::BoundaryPaddedArray...)
@@ -95,6 +98,7 @@ ComposedBoundaryPaddedMatrix{T,V,B} = ComposedBoundaryPaddedArray{T,2,1,V,B}
9598
ComposedBoundaryPadded3Tensor{T,V,B} = ComposedBoundaryPaddedArray{T,3,2,V,B}
9699

97100
Base.size(Q::ComposedBoundaryPaddedArray) = size(Q.u).+2
101+
unpadded_size(Q::ComposedBoundaryPaddedArray) = size(Q.u)
98102

99103
"""
100104
Ax, Ay,... = decompose(A::ComposedBoundaryPaddedArray)

src/composite_operators.jl

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ struct DiffEqScaledOperator{T,F,OpType<:AbstractDiffEqLinearOperator{T}} <: Abst
1717
op::OpType
1818
end
1919
*::DiffEqScalar{T,F}, L::AbstractDiffEqLinearOperator{T}) where {T,F} = DiffEqScaledOperator(α, L)
20+
*::Number, L::AbstractDiffEqLinearOperator{T}) where T = DiffEqScaledOperator(DiffEqScalar(convert(T,α)), L)
2021
-(L::AbstractDiffEqLinearOperator{T}) where {T} = DiffEqScalar(-one(T)) * L
2122
getops(L::DiffEqScaledOperator) = (L.coeff, L.op)
2223
Matrix(L::DiffEqScaledOperator) = L.coeff * Matrix(L.op)
@@ -27,15 +28,19 @@ opnorm(L::DiffEqScaledOperator, p::Real=2) = abs(L.coeff) * opnorm(L.op, p)
2728
getindex(L::DiffEqScaledOperator, i::Int) = L.coeff * L.op[i]
2829
getindex(L::DiffEqScaledOperator, I::Vararg{Int, N}) where {N} =
2930
L.coeff * L.op[I...]
30-
*(L::DiffEqScaledOperator, x::AbstractVecOrMat) = L.coeff * (L.op * x)
31-
*(x::AbstractVecOrMat, L::DiffEqScaledOperator) = (L.op * x) * L.coeff
32-
/(L::DiffEqScaledOperator, x::AbstractVecOrMat) = L.coeff * (L.op / x)
33-
/(x::AbstractVecOrMat, L::DiffEqScaledOperator) = 1/L.coeff * (x / L.op)
34-
\(L::DiffEqScaledOperator, x::AbstractVecOrMat) = 1/L.coeff * (L.op \ x)
35-
\(x::AbstractVecOrMat, L::DiffEqScaledOperator) = L.coeff * (x \ L)
36-
mul!(Y::AbstractVecOrMat, L::DiffEqScaledOperator, B::AbstractVecOrMat) =
37-
lmul!(L.coeff, mul!(Y, L.op, B))
38-
ldiv!(Y::AbstractVecOrMat, L::DiffEqScaledOperator, B::AbstractVecOrMat) =
31+
*(L::DiffEqScaledOperator, x::AbstractArray) = L.coeff * (L.op * x)
32+
*(x::AbstractArray, L::DiffEqScaledOperator) = (L.op * x) * L.coeff
33+
/(L::DiffEqScaledOperator, x::AbstractArray) = L.coeff * (L.op / x)
34+
/(x::AbstractArray, L::DiffEqScaledOperator) = 1/L.coeff * (x / L.op)
35+
\(L::DiffEqScaledOperator, x::AbstractArray) = 1/L.coeff * (L.op \ x)
36+
\(x::AbstractArray, L::DiffEqScaledOperator) = L.coeff * (x \ L)
37+
for N in (2,3)
38+
@eval begin
39+
mul!(Y::AbstractArray{T,$N}, L::DiffEqScaledOperator{T}, B::AbstractArray{T,$N}) where {T} =
40+
lmul!(Y, L.coeff, mul!(Y, L.op, B))
41+
end
42+
end
43+
ldiv!(Y::AbstractArray, L::DiffEqScaledOperator, B::AbstractArray) =
3944
lmul!(1/L.coeff, ldiv!(Y, L.op, B))
4045
factorize(L::DiffEqScaledOperator) = L.coeff * factorize(L.op)
4146
for fact in (:lu, :lu!, :qr, :qr!, :cholesky, :cholesky!, :ldlt, :ldlt!,
@@ -46,18 +51,19 @@ end
4651

4752
# Linear Combination
4853
struct DiffEqOperatorCombination{T,O<:Tuple{Vararg{AbstractDiffEqLinearOperator{T}}},
49-
C<:AbstractVector{T}} <: AbstractDiffEqCompositeOperator{T}
50-
ops::O
51-
cache::C
52-
function DiffEqOperatorCombination(ops; cache=nothing)
53-
T = eltype(ops[1])
54-
if cache == nothing
55-
cache = Vector{T}(undef, size(ops[1], 1))
56-
fill!(cache,0)
54+
C<:AbstractVector{T}} <: AbstractDiffEqCompositeOperator{T}
55+
ops::O
56+
cache::C
57+
function DiffEqOperatorCombination(ops; cache=nothing)
58+
T = eltype(ops[1])
59+
for i in 2:length(ops)
60+
@assert size(ops[i]) == size(ops[1]) "Operators must be of the same size to be combined! Mismatch between $(ops[i]) and $(ops[i-1]), which are operators $i and $(i-1) respectively"
61+
end
62+
if cache == nothing
63+
cache = zeros(T, size(ops[1], 1))
64+
end
65+
new{T,typeof(ops),typeof(cache)}(ops, cache)
5766
end
58-
# TODO: safecheck dimensions
59-
new{T,typeof(ops),typeof(cache)}(ops, cache)
60-
end
6167
end
6268
+(ops::AbstractDiffEqLinearOperator...) = DiffEqOperatorCombination(ops)
6369
+(L1::DiffEqOperatorCombination, L2::AbstractDiffEqLinearOperator) = DiffEqOperatorCombination((L1.ops..., L2))
@@ -72,10 +78,10 @@ convert(::Type{AbstractMatrix}, L::DiffEqOperatorCombination) =
7278
size(L::DiffEqOperatorCombination, args...) = size(L.ops[1], args...)
7379
getindex(L::DiffEqOperatorCombination, i::Int) = sum(op -> op[i], L.ops)
7480
getindex(L::DiffEqOperatorCombination, I::Vararg{Int, N}) where {N} = sum(op -> op[I...], L.ops)
75-
*(L::DiffEqOperatorCombination, x::AbstractVecOrMat) = sum(op -> op * x, L.ops)
76-
*(x::AbstractVecOrMat, L::DiffEqOperatorCombination) = sum(op -> x * op, L.ops)
77-
/(L::DiffEqOperatorCombination, x::AbstractVecOrMat) = sum(op -> op / x, L.ops)
78-
\(x::AbstractVecOrMat, L::DiffEqOperatorCombination) = sum(op -> x \ op, L.ops)
81+
*(L::DiffEqOperatorCombination, x::AbstractArray) = sum(op -> op * x, L.ops)
82+
*(x::AbstractArray, L::DiffEqOperatorCombination) = sum(op -> x * op, L.ops)
83+
/(L::DiffEqOperatorCombination, x::AbstractArray) = sum(op -> op / x, L.ops)
84+
\(x::AbstractArray, L::DiffEqOperatorCombination) = sum(op -> x \ op, L.ops)
7985
function mul!(y::AbstractVector, L::DiffEqOperatorCombination, b::AbstractVector)
8086
mul!(y, L.ops[1], b)
8187
for op in L.ops[2:end]
@@ -92,7 +98,10 @@ struct DiffEqOperatorComposition{T,O<:Tuple{Vararg{AbstractDiffEqLinearOperator{
9298
caches::C
9399
function DiffEqOperatorComposition(ops; caches=nothing)
94100
T = eltype(ops[1])
95-
# TODO: safecheck dimensions
101+
for i in 2:length(ops)
102+
@assert size(ops[i-1], 1) == size(ops[i], 2) "Operations do not have compatable sizes! Mismatch between $(ops[i]) and $(ops[i-1]), which are operators $i and $(i-1) respectively."
103+
end
104+
96105
if caches == nothing
97106
# Construct a list of caches to be used by mul! and ldiv!
98107
caches = []
@@ -122,12 +131,12 @@ convert(::Type{AbstractMatrix}, L::DiffEqOperatorComposition) =
122131
size(L::DiffEqOperatorComposition) = (size(L.ops[end], 1), size(L.ops[1], 2))
123132
size(L::DiffEqOperatorComposition, m::Integer) = size(L)[m]
124133
opnorm(L::DiffEqOperatorComposition) = prod(opnorm, L.ops)
125-
*(L::DiffEqOperatorComposition, x::AbstractVecOrMat) = foldl((acc, op) -> op*acc, L.ops; init=x)
126-
*(x::AbstractVecOrMat, L::DiffEqOperatorComposition) = foldl((acc, op) -> acc*op, reverse(L.ops); init=x)
127-
/(L::DiffEqOperatorComposition, x::AbstractVecOrMat) = foldl((acc, op) -> op/acc, L.ops; init=x)
128-
/(x::AbstractVecOrMat, L::DiffEqOperatorComposition) = foldl((acc, op) -> acc/op, L.ops; init=x)
129-
\(L::DiffEqOperatorComposition, x::AbstractVecOrMat) = foldl((acc, op) -> op\acc, reverse(L.ops); init=x)
130-
\(x::AbstractVecOrMat, L::DiffEqOperatorComposition) = foldl((acc, op) -> acc\op, reverse(L.ops); init=x)
134+
*(L::DiffEqOperatorComposition, x::AbstractArray) = foldl((acc, op) -> op*acc, L.ops; init=x)
135+
*(x::AbstractArray, L::DiffEqOperatorComposition) = foldl((acc, op) -> acc*op, reverse(L.ops); init=x)
136+
/(L::DiffEqOperatorComposition, x::AbstractArray) = foldl((acc, op) -> op/acc, L.ops; init=x)
137+
/(x::AbstractArray, L::DiffEqOperatorComposition) = foldl((acc, op) -> acc/op, L.ops; init=x)
138+
\(L::DiffEqOperatorComposition, x::AbstractArray) = foldl((acc, op) -> op\acc, reverse(L.ops); init=x)
139+
\(x::AbstractArray, L::DiffEqOperatorComposition) = foldl((acc, op) -> acc\op, reverse(L.ops); init=x)
131140
function mul!(y::AbstractVector, L::DiffEqOperatorComposition, b::AbstractVector)
132141
mul!(L.caches[1], L.ops[1], b)
133142
for i in 2:length(L.ops) - 1
Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
abstract type AbstractBC{T} <: AbstractDiffEqLinearOperator{T} end
1+
abstract type AbstractBC{T} <: AbstractDiffEqAffineOperator{T} end
22

33

44
abstract type AtomicBC{T} <: AbstractBC{T} end
@@ -14,9 +14,32 @@ struct NeumannBC{N} end
1414
struct Neumann0BC{N} end
1515
struct DirichletBC{N} end
1616
struct Dirichlet0BC{N} end
17+
18+
"""
19+
q = PeriodicBC{T}()
20+
Qx, Qy, ... = PeriodicBC{T}(size(u)) #When all dimensions are to be extended with a periodic boundary condition.
21+
-------------------------------------------------------------------------------------
22+
Creates a periodic boundary condition, where the lower index end of some u is extended with the upper index end and vice versa.
23+
It is not reccomended to concretize this BC type in to a BandedMatrix, since the vast majority of bands will be all 0s. SpatseMatrix concretization is reccomended.
24+
"""
1725
struct PeriodicBC{T} <: AtomicBC{T}
1826
PeriodicBC(T::Type) = new{T}()
1927
end
28+
29+
"""
30+
q = RobinBC(left_coefficients, right_coefficients, dx::T, approximation_order) where T # When this BC extends a dimension with a uniform step size
31+
q = RobinBC(left_coefficients, right_coefficients, dx::Vector{T}, approximation_order) where T # When this BC extends a dimension with a non uniform step size. dx should be the vector of step sizes for the whole dimension
32+
-------------------------------------------------------------------------------------
33+
The variables in l are [αl, βl, γl], and correspond to a BC of the form αl*u(0) + βl*u'(0) = γl imposed on the lower index boundary.
34+
The variables in r are [αl, βl, γl], and correspond to an analagous boundary on the higher index end.
35+
Implements a robin boundary condition operator Q that acts on a vector to give an extended vector as a result
36+
Referring to (https://github.com/JuliaDiffEq/DiffEqOperators.jl/files/3267835/ghost_node.pdf)
37+
Write vector b̄₁ as a vertical concatanation with b0 and the rest of the elements of b̄ ₁, denoted b̄`₁, the same with ū into u0 and ū`. b̄`₁ = b̄`_2 = fill(β/Δx, length(stencil)-1)
38+
Pull out the product of u0 and b0 from the dot product. The stencil used to approximate u` is denoted s. b0 = α+(β/Δx)*s[1]
39+
Rearrange terms to find a general formula for u0:= -b̄`₁̇⋅ū`/b0 + γ/b0, which is dependent on ū` the robin coefficients and Δx.
40+
The non identity part of Qa is qa:= -b`₁/b0 = -β.*s[2:end]/(α+β*s[1]/Δx). The constant part is Qb = γ/(α+β*s[1]/Δx)
41+
do the same at the other boundary (amounts to a flip of s[2:end], with the other set of boundary coeffs)
42+
"""
2043
struct RobinBC{T, V<:AbstractVector{T}} <: AffineBC{T}
2144
a_l::V
2245
b_l::T
@@ -57,8 +80,11 @@ struct RobinBC{T, V<:AbstractVector{T}} <: AffineBC{T}
5780
end
5881
end
5982

83+
stencil(q::AffineBC{T}, N::Int) where T = ([transpose(q.a_l) transpose(zeros(T, N-length(q.a_l)))], [transpose(zeros(T, N-length(q.a_r))) transpose(q.a_r)])
84+
affine(q::AffineBC) = (q.b_l, q.b_r)
6085

61-
86+
stencil(q::PeriodicBC{T}, N::Int) where T= ([transpose(zeros(T, N-1)) one(T)], [one(T) transpose(zeros(T, N-1))])
87+
affine(q::PeriodicBC{T}) where T = (zero(T), zero(T))
6288
"""
6389
q = GeneralBC(α_leftboundary, α_rightboundary, dx::T, approximation_order)
6490

0 commit comments

Comments
 (0)