-
-
Notifications
You must be signed in to change notification settings - Fork 72
[WIP] Correct concretization BCs and ghost derivative operators #185
base: master
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -101,7 +101,10 @@ end | |||||
| # Boundary Condition Operator concretizations | ||||||
| ################################################################################ | ||||||
|
|
||||||
| #Atomic BCs | ||||||
| # * Atomic BCs | ||||||
|
|
||||||
| # ** Affine BCs | ||||||
|
|
||||||
| function LinearAlgebra.Array(Q::AffineBC{T}, N::Int) where {T} | ||||||
| Q_L = [transpose(Q.a_l) transpose(zeros(T, N-length(Q.a_l))); Diagonal(ones(T,N)); transpose(zeros(T, N-length(Q.a_r))) transpose(Q.a_r)] | ||||||
| Q_b = [Q.b_l; zeros(T,N); Q.b_r] | ||||||
|
|
@@ -115,45 +118,74 @@ function SparseArrays.SparseMatrixCSC(Q::AffineBC{T}, N::Int) where {T} | |||||
| end | ||||||
|
|
||||||
| function BandedMatrices.BandedMatrix(Q::AffineBC{T}, N::Int) where {T} | ||||||
| Q_l = BandedMatrix{T}(Eye(N), (length(Q.a_r)-1, length(Q.a_l)-1)) | ||||||
| BandedMatrices.inbands_setindex!(Q_l, Q.a_l, 1, 1:length(Q.a_l)) | ||||||
| BandedMatrices.inbands_setindex!(Q_l, Q.a_r, N, (N-length(Q.a_r)+1):N) | ||||||
| # We want the concrete matrix to have as small bandwidths as | ||||||
| # possible, and we accomplish this by dropping all trailing | ||||||
| # zeros. This way, we do not write outside the bands of the | ||||||
| # BandedMatrix. | ||||||
| a_r = Q.a_r[1:something(findlast(!iszero, Q.a_r), 0)] | ||||||
| a_l = Q.a_l[1:something(findlast(!iszero, Q.a_l), 0)] | ||||||
|
|
||||||
| # Compute bandwidths; the BC matrix should have the shape | ||||||
| # | ||||||
| # [a b c ... | ||||||
| # 1 | ||||||
| # 1 | ||||||
| # 1 | ||||||
| # . | ||||||
| # 1 | ||||||
| # ... x y z] | ||||||
| # | ||||||
| # where a,b,c,... and ...,x,y,z are determined by the boundary | ||||||
| # conditions. If these coefficients are zero (Dirichlet0BC), then | ||||||
| # the proper bandwidths are (l,u) = (1,-1). | ||||||
| l = max(count(!iszero, a_r)+1, 1) | ||||||
| u = max(count(!iszero, a_l)-1, -1) | ||||||
|
|
||||||
| Q_l = BandedMatrix((-1 => ones(T,N),), (N+2,N), (l, u)) | ||||||
| for (j,e) ∈ enumerate(a_l) | ||||||
| BandedMatrices.inbands_setindex!(Q_l, e, 1, j) | ||||||
| end | ||||||
| for (j,e) ∈ enumerate(a_r) | ||||||
| BandedMatrices.inbands_setindex!(Q_l, e, N+2, N-length(a_r)+j) | ||||||
| end | ||||||
| Q_b = [Q.b_l; zeros(T,N); Q.b_r] | ||||||
| return (Q_l, Q_b) | ||||||
|
|
||||||
| Q_l, Q_b | ||||||
| end | ||||||
|
|
||||||
| function SparseArrays.sparse(Q::AffineBC{T}, N::Int) where {T} | ||||||
| SparseMatrixCSC(Q,N) | ||||||
| end | ||||||
| """ | ||||||
| sparse(Q::AffineBC, N) | ||||||
|
|
||||||
| LinearAlgebra.Array(Q::PeriodicBC{T}, N::Int) where T = (Array([transpose(zeros(T, N-1)) one(T); Diagonal(ones(T,N)); one(T) transpose(zeros(T, N-1))]), zeros(T, N)) | ||||||
| SparseArrays.SparseMatrixCSC(Q::PeriodicBC{T}, N::Int) where T = ([transpose(zeros(T, N-1)) one(T); Diagonal(ones(T,N)); one(T) transpose(zeros(T, N-1))], zeros(T, N)) | ||||||
| SparseArrays.sparse(Q::PeriodicBC{T}, N::Int) where T = SparseMatrixCSC(Q,N) | ||||||
| function BandedMatrices.BandedMatrix(Q::PeriodicBC{T}, N::Int) where T #Not reccomended! | ||||||
| Q_array = BandedMatrix{T}(Eye(N), (N-1, N-1)) | ||||||
| Q_array[1, end] = one(T) | ||||||
| Q_array[1, 1] = zero(T) | ||||||
| Q_array[end, 1] = one(T) | ||||||
| Q_array[end, end] = zero(T) | ||||||
|
|
||||||
| return (Q_array, zeros(T, N)) | ||||||
| end | ||||||
| Since affine boundary conditions are representable by banded matrices, | ||||||
| that is the default sparse concretization; if you want a | ||||||
| `SparseMatrixCSC`, use `SparseMatrixCSC(Q, N)` instead. | ||||||
| """ | ||||||
| SparseArrays.sparse(Q::AffineBC, N::Int) = BandedMatrix(Q,N) | ||||||
|
|
||||||
| function LinearAlgebra.Array(Q::BoundaryPaddedVector) | ||||||
| return [Q.l; Q.u; Q.r] | ||||||
| end | ||||||
| # ** Periodic BCs | ||||||
|
|
||||||
| function Base.convert(::Type{Array},A::AbstractBC{T}) where T | ||||||
| Array(A) | ||||||
| end | ||||||
| LinearAlgebra.Array(Q::PeriodicBC{T}, N::Int) where T = | ||||||
| ([transpose(zeros(T, N-1)) one(T) | ||||||
| Diagonal(ones(T,N)) | ||||||
| one(T) transpose(zeros(T, N-1))], | ||||||
| zeros(T,N+2)) | ||||||
|
|
||||||
| function Base.convert(::Type{SparseMatrixCSC},A::AbstractBC{T}) where T | ||||||
| SparseMatrixCSC(A) | ||||||
| end | ||||||
| SparseArrays.SparseMatrixCSC(Q::PeriodicBC{T}, N::Int) where T = | ||||||
| (vcat(hcat(zeros(T, 1,N-1), one(T)), | ||||||
| Diagonal(ones(T,N)), | ||||||
| hcat(one(T), zeros(T, 1, N-1))), | ||||||
| zeros(T,N+2)) | ||||||
|
|
||||||
| function Base.convert(::Type{AbstractMatrix},A::AbstractBC{T}) where T | ||||||
| SparseMatrixCSC(A) | ||||||
| end | ||||||
| SparseArrays.sparse(Q::PeriodicBC{T}, N::Int) where T = SparseMatrixCSC(Q,N) | ||||||
|
|
||||||
| BandedMatrices.BandedMatrix(::PeriodicBC, ::Int) = | ||||||
| throw(ArgumentError("Periodic boundary conditions should be concretized as sparse matrices")) | ||||||
|
|
||||||
| LinearAlgebra.Array(Q::BoundaryPaddedVector) = [Q.l; Q.u; Q.r] | ||||||
|
|
||||||
| Base.convert(::Type{Array},A::AbstractBC) = Array(A) | ||||||
| Base.convert(::Type{SparseMatrixCSC},A::AbstractBC) = SparseMatrixCSC(A) | ||||||
| Base.convert(::Type{AbstractMatrix},A::AbstractBC) = SparseMatrixCSC(A) | ||||||
|
||||||
| Base.convert(::Type{AbstractMatrix},A::AbstractBC) = SparseMatrixCSC(A) | |
| Base.convert(::Type{AbstractMatrix},A::AbstractBC) = sparse(A) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| using SparseArrays, DiffEqOperators, LinearAlgebra, Random, | ||
| Test, BandedMatrices, FillArrays, LazyArrays, BlockBandedMatrices, Compat | ||
|
|
||
| @testset "Concretizations of BCs" begin | ||
| T = Float64 | ||
| L = 10one(T) | ||
| N = 9 | ||
| δx = L/(N+1) | ||
|
|
||
| @testset "Affine BCs" begin | ||
| @testset "Dirichlet0BC" begin | ||
| Q = Dirichlet0BC(T) | ||
|
|
||
| correct = vcat(zeros(T,1,N), | ||
| Diagonal(ones(T,N)), | ||
| zeros(T,1,N)) | ||
|
|
||
| @testset "$mode concretization" for (mode,Mat,Expected,ExpectedBandwidths) in [ | ||
| ("sparse -> Banded", sparse, BandedMatrix{T}, (1,-1)), | ||
| ("Banded", BandedMatrix, BandedMatrix{T}, (1,-1)), | ||
| ("Sparse", SparseMatrixCSC, SparseMatrixCSC{T}, nothing), | ||
| ("Dense", Array, Matrix{T}, nothing) | ||
| ] | ||
| Qm,Qu = Mat(Q,N) | ||
|
|
||
| @test Qm == correct | ||
ChrisRackauckas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @test Qm isa Expected | ||
| @test Qu == zeros(T,N+2) | ||
|
|
||
| !isnothing(ExpectedBandwidths) && | ||
| @test bandwidths(Qm) == ExpectedBandwidths | ||
| end | ||
| end | ||
|
|
||
| @testset "Neumann0BC" begin | ||
| Q = Neumann0BC(δx) | ||
|
|
||
| correct = vcat(hcat(one(T),zeros(T,1,N-1)), | ||
| Diagonal(ones(T,N)), | ||
| hcat(zeros(T,1,N-1),one(T))) | ||
|
|
||
| @testset "$mode concretization" for (mode,Mat,Expected,ExpectedBandwidths) in [ | ||
| ("sparse -> Banded", sparse, BandedMatrix{T}, (2,0)), | ||
| ("Banded", BandedMatrix, BandedMatrix{T}, (2,0)), | ||
| ("Sparse", SparseMatrixCSC, SparseMatrixCSC{T}, nothing), | ||
| ("Dense", Array, Matrix{T}, nothing) | ||
| ] | ||
| Qm,Qu = Mat(Q,N) | ||
|
|
||
| @test Qm == correct | ||
| @test Qm isa Expected | ||
| @test Qu == zeros(T,N+2) | ||
|
|
||
| !isnothing(ExpectedBandwidths) && | ||
| @test bandwidths(Qm) == ExpectedBandwidths | ||
| end | ||
|
|
||
| @testset "Banded concretization, extra zeros" begin | ||
| @testset "lz = $lz" for lz = 0:3 | ||
| @testset "rz = $rz" for rz = 0:3 | ||
| Q′ = Neumann0BC(δx) | ||
| # Artificially add some zero coefficients, which should | ||
| # not increase the bandwidth of the concretized BC. | ||
| append!(Q′.a_l, zeros(lz)) | ||
| append!(Q′.a_r, zeros(rz)) | ||
|
|
||
| Q′m,Q′u = sparse(Q′,N) | ||
| @test bandwidths(Q′m) == (2,0) | ||
|
|
||
| @test Q′m == correct | ||
| @test Q′u == zeros(T,N+2) | ||
| end | ||
| end | ||
| end | ||
| end | ||
|
|
||
| @testset "General BCs" begin | ||
| @testset "Left BC order = $ld" for ld = 2:5 | ||
| @testset "Right BC order = $rd" for rd = 2:5 | ||
| αl = 0.0:ld-1 | ||
| αr = 0.0:rd-1 | ||
|
|
||
| Q = GeneralBC(αl, αr, δx) | ||
|
|
||
| correct = vcat(hcat(Q.a_l',zeros(T,1,N-(ld-2))), | ||
| Diagonal(ones(T,N)), | ||
| hcat(zeros(T,1,N-(rd-2)),Q.a_r')) | ||
|
|
||
| Qm,Qu = sparse(Q,N) | ||
|
|
||
| @test Qm == correct | ||
| @test Qm isa BandedMatrix{T} | ||
| @test bandwidths(Qm) == (rd-1,ld-3) | ||
|
|
||
| @test Qu == vcat(Q.b_l,zeros(T,N),Q.b_r) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| @testset "Dirichlet0BC" begin | ||
| # This is equivalent to a Dirichlet0BC; the trailing zeros | ||
| # should be dropped and the bandwidths optimal. | ||
| Q = GeneralBC([0.0, 1.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0, 0.0], δx) | ||
|
|
||
| correct = vcat(zeros(T,1,N), | ||
| Diagonal(ones(T,N)), | ||
| zeros(T,1,N)) | ||
|
|
||
| Qm = first(sparse(Q,N)) | ||
| @test Qm == correct | ||
| @test bandwidths(Qm) == (1,-1) | ||
| end | ||
|
|
||
| @testset "Almost DirichletBC" begin | ||
| Q = GeneralBC([1.0, 1.0, 0.0, 0.0, eps(Float64)], | ||
| [1.0, 1.0, 0.0, 0.0, 0.0], δx) | ||
|
|
||
| correct = vcat(zeros(T,1,N), | ||
| Diagonal(ones(T,N)), | ||
| zeros(T,1,N)) | ||
|
|
||
| Qm,Qu = sparse(Q,N) | ||
|
|
||
| @test Qm ≈ correct | ||
| @test bandwidths(Qm) == (1,2) | ||
| @test Qu ≈ vcat(-one(T),zeros(T,N),-one(T)) | ||
| end | ||
| end | ||
|
|
||
| @testset "Periodic BCs" begin | ||
| Q = PeriodicBC(T) | ||
| @test_throws ArgumentError BandedMatrix(Q,N) | ||
|
|
||
| correct = vcat(hcat(zeros(T,1,N-1),one(T)), | ||
| Diagonal(ones(T,N)), | ||
| hcat(one(T),zeros(T,1,N-1))) | ||
|
|
||
| @testset "Sparse concretization" begin | ||
| Qm,Qu = SparseMatrixCSC(Q,N) | ||
|
|
||
| @test Qm == correct | ||
| @test Qm isa SparseMatrixCSC{T} | ||
| @test Qu == zeros(T,N+2) | ||
|
|
||
| Qm′ = first(sparse(Q, N)) | ||
| @test Qm′ == correct | ||
| @test Qm′ isa SparseMatrixCSC{T} | ||
| end | ||
|
|
||
| @testset "Dense concretization" begin | ||
| Qm,Qu = Array(Q,N) | ||
|
|
||
| @test Qm == correct | ||
| @test Qm isa Matrix{T} | ||
| @test Qu == zeros(T,N+2) | ||
| end | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't this
something(findfirst(!iszero, Q.a_r):end?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't know :) I have not thought about this PR since September.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed hat I had started a review and not submitted it, probably also since September - better late than never :P