|
| 1 | +abstract type AbstractBC{T} end |
| 2 | + |
| 3 | +# robin, general, and in general neumann BCs are all affine. neumann0 is not however; is a specialization needed? |
| 4 | +abstract type AffineBC{T,V} <: AbstractBC{T} end |
| 5 | + |
| 6 | +struct DirichletBC{T} <: AbstractBC{T} |
| 7 | + l::T |
| 8 | + r::T |
| 9 | +end |
| 10 | + |
| 11 | +struct NeumannBC{T, V<:AbstractArray{T}} <: AffineBC{T,V} |
| 12 | + a_l::V |
| 13 | + b_l::T |
| 14 | + a_r::V |
| 15 | + b_r::T |
| 16 | + function NeumannBC(l::T, r::T, dx::AbstractArray{T}, order::T = one(T)) where {T,V} |
| 17 | + s = calculate_weights(1, zero(T), zero(T):order) #generate derivative coefficients about the boundary of required approximation order |
| 18 | + |
| 19 | + a_l = -dx_l.*s[2:end]./s[1] |
| 20 | + a_r = -dx_r.*s[end:-1:2]./s[1] |
| 21 | + |
| 22 | + b_l = dx_l.*l./s[1] |
| 23 | + b_r = dx_r.*l./s[1] |
| 24 | + |
| 25 | + return new{T, typeof(a_l)}(a_l, b_l, a_r, b_r) |
| 26 | + end |
| 27 | +end |
| 28 | + |
| 29 | +struct PeriodicBC{T} <: AbstractBC{T} |
| 30 | + |
| 31 | +end |
| 32 | + |
| 33 | +""" |
| 34 | + Implements a robin boundary condition operator Q that acts on a vector to give an extended vector as a result |
| 35 | + Referring to (https://github.com/JuliaDiffEq/DiffEqOperators.jl/files/3267835/ghost_node.pdf) |
| 36 | +
|
| 37 | + the variables in correspond to al*u(0) + bl*u'(0) = cl |
| 38 | +
|
| 39 | +
|
| 40 | + Write vector b̄_1 as a vertical concatanation with b0 and the rest of the elements of b̄_1, denoted b̄`_1, the same with ū into u0 and ū`. b̄` = fill(β/Δx, length(stencil)-1) |
| 41 | + 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] |
| 42 | + Rearrange terms to find a general formula for u0:= -b̄`_1̇⋅ū`/b0 + γ/b0 , the robin coefficients and Δx. |
| 43 | + The non identity part of Qa is qa:= -b`_1/b0 = -β.*s[2:end]/(α+β*s[1]/Δx). The constant part is Qb = γ/(α+β*s[1]/Δx) |
| 44 | + do the same at the other boundary (amounts to a flip in s.) |
| 45 | +""" |
| 46 | + |
| 47 | +# For condition, the variables correspond to al*u(0) + bl*u'(0) = cl |
| 48 | +# this should not break |
| 49 | +struct RobinBC{T, V<:AbstractVector{T}} <: AffineBC{T,V} |
| 50 | + a_l::V |
| 51 | + b_l::T |
| 52 | + a_r::V |
| 53 | + b_r::T |
| 54 | + function RobinBC(l::AbstractArray{T}, r::AbstractArray{T}, dx::AbstractArray{T}, order::T = one(T)) where {T,V} |
| 55 | + cl, al, bl = l |
| 56 | + cr, ar, br = r |
| 57 | + dx_l, dx_r = dx |
| 58 | + |
| 59 | + s = calculate_weights(1, zero(T), zero(T):order) #generate derivative coefficients about the boundary of required approximation order |
| 60 | + |
| 61 | + a_l = -bl.*s[2:end]./(al .+ bl*s[1]./dx_l) |
| 62 | + a_r = -br.*s[end:-1:2]./(ar .+ br*s[1]./dx_r) |
| 63 | + |
| 64 | + b_l = cl/(al+bl*s[1]/dx_l) |
| 65 | + b_r = cr/(ar+br*s[1]/dx_r) |
| 66 | + |
| 67 | + return new{T, typeof(a_l)}(a_l, b_l, a_r, b_r) |
| 68 | + end |
| 69 | +end |
| 70 | + |
| 71 | +""" |
| 72 | +Implements a generalization of the Robin boundary condition, where α is a vector of coefficients. |
| 73 | +Represents a condition of the form α[1] + α[2]u[0] + α[3]u'[0] + α[4]u''[0]+... = 0 |
| 74 | +Implemented in an analogous way to the RobinBC |
| 75 | +""" |
| 76 | +#If you know a more correct name for this kind of BC, please post an issue/PR |
| 77 | +struct GeneralBC{T, V<:AbstractVector{T}} <:AffineBC{T,V} |
| 78 | + a_l::V |
| 79 | + b_l::T |
| 80 | + a_r::V |
| 81 | + b_r::T |
| 82 | + function GeneralBC{T,V}(αl::AbstractArray{T}, αr::AbstractArray{T}, dx::AbstractArray{T}, order::T = one(T)) where {T,V<:AbstractArray} |
| 83 | + dx_l, dx_r = dx |
| 84 | + nl = length(αl) |
| 85 | + nr = length(αr) |
| 86 | + S_l = zeros(T, (nl-2, order+nl-2)) |
| 87 | + S_r = zeros(T, (nr-2, order+nr-2)) |
| 88 | + |
| 89 | + for i in 1:(nl-2) |
| 90 | + S_l[i,:] = [transpose(calculate_weights(i, zero(T), zero(T):(order+i))) transpose(zeros(T, nl-2-i))] #am unsure if the length of the dummy_x is correct here |
| 91 | + end |
| 92 | + for i in 1:(nr-2) |
| 93 | + S_r[i,:] = [transpose(calculate_weights(i, zero(T), zero(T):(order+i))) transpose(zeros(T, nr-2-i))] |
| 94 | + end |
| 95 | + s0_l = S_l[:,1] ; Sl = S_l[2:end,:] |
| 96 | + s0_r = S_r[:,1] ; Sr = S_r[2:end,:] |
| 97 | + |
| 98 | + denoml = αl[2] .+ αl[3:end] ⋅ s0_l |
| 99 | + denomr = αr[2] .+ αr[3:end] ⋅ s0_r |
| 100 | + |
| 101 | + a_l = -transpose(αl) ⋅ Sl ./denoml |
| 102 | + a_r = -transpose(αr) ⋅ Sr ./denomr |
| 103 | + |
| 104 | + b_l = -αl[1]/denoml |
| 105 | + b_r = -αr[1]/denomr |
| 106 | + new{T, V}(a_l,b_l,reverse!(a_r),b_r) |
| 107 | + end |
| 108 | +end |
| 109 | + |
| 110 | +# other acceptable argument signatures |
| 111 | +RobinBC(al::T, bl::T, cl::T, dx_l::T, ar::T, br::T, cr::T, dx_r::T) where T = RobinBC([al,bl,cl], [ar, br, cr], [dx_l, dx_r]) |
| 112 | +RobinBC(al::T, bl::T, cl::T, dx_l::T, ar::T, br::T, cr::T, dx_r::T, order::T) where T = RobinBC([al,bl,cl], [ar, br, cr], [dx_l, dx_r], order) |
| 113 | + |
| 114 | +NeumannBC(l::T, dx_l::T, r::T, dx_r::T) where T = NeumannBC(l, r, [dx_l,dx_r]) |
| 115 | +NeumannBC(l::T, dx_l::T, r::T, dx_r::T, order::T) where T = NeumannBC(l, r, [dx_l,dx_r], order) |
| 116 | +# this is 'boundary padded vector' as opposed to 'boundary padded array' to distinguish it from the n dimensional implementation that will eventually be neeeded |
| 117 | +struct BoundaryPaddedVector{T,T2 <: AbstractVector{T}} |
| 118 | + l::T |
| 119 | + r::T |
| 120 | + u::T2 |
| 121 | +end |
| 122 | + |
| 123 | + |
| 124 | +Base.:*(Q::DirichletBC, u) = BoundaryPaddedVector(Q.l,Q.r,u) |
| 125 | +Base.:*(Q::PeriodicBC, u) = BoundaryPaddedVector(u[end], u[1], u) |
| 126 | +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) |
| 127 | + |
| 128 | +Base.size(Q::AbstractBC) = (Inf, Inf) #Is this nessecary? |
| 129 | +Base.length(Q::BoundaryPaddedVector) = length(Q.u) + 2 |
| 130 | +Base.lastindex(Q::BoundaryPaddedVector) = Base.length(Q) |
| 131 | + |
| 132 | +function Base.getindex(Q::BoundaryPaddedVector,i) |
| 133 | + @show i |
| 134 | + if i == 1 |
| 135 | + return Q.l |
| 136 | + elseif i == length(Q) |
| 137 | + return Q.r |
| 138 | + else |
| 139 | + return Q.u[i-1] |
| 140 | + end |
| 141 | +end |
| 142 | + |
| 143 | +function LinearAlgebra.Array(Q::AffineBC, N::Int) |
| 144 | + Q_L = [transpose(Q.a_l) transpose(zeros(N-length(Q.a_l))); Diagonal(ones(N)); transpose(zeros(N-length(Q.a_r))) transpose(Q.a_r)] |
| 145 | + Q_b = [Q.b_l; zeros(N); Q.b_r] |
| 146 | + return (Q_L, Q_b) |
| 147 | +end |
| 148 | + |
| 149 | +function LinearAlgebra.Array(Q::BoundaryPaddedVector) |
| 150 | + return [Q.l; Q.u; Q.r] |
| 151 | +end |
0 commit comments