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

Commit 2a3885f

Browse files
committed
split out multi dimensional BCs in to their own file for readability
1 parent 47af0e1 commit 2a3885f

File tree

2 files changed

+278
-279
lines changed

2 files changed

+278
-279
lines changed

src/derivative_operators/BC_operators.jl

Lines changed: 0 additions & 279 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ abstract type AbstractBC{T} <: AbstractDiffEqLinearOperator{T} end
33

44
abstract type AtomicBC{T} <: AbstractBC{T} end
55

6-
abstract type MultiDimensionalBC{T, N} <: AbstractBC{T} end
7-
86
"""
97
Robin, General, and in general Neumann, Dirichlet and Bridge BCs are all affine opeartors, meaning that they take the form Q*x = Qa*x + Qb.
108
"""
@@ -280,280 +278,3 @@ Base.:*(Q::PeriodicBC, u::AbstractVector) = BoundaryPaddedVector(u[end], u[1], u
280278
Base.size(Q::AtomicBC) = (Inf, Inf) #Is this nessecary?
281279

282280
gettype(Q::AbstractBC{T}) where T = T
283-
284-
285-
#######################################################################
286-
# Multidimensional
287-
#######################################################################
288-
289-
"""
290-
slicemul is the only limitation on the BCs here being used up to arbitrary dimension, an N dimensional implementation is needed.
291-
"""
292-
@inline function slicemul(A::Array{B,1}, u::AbstractArray{T, 2}, dim::Integer) where {T, B<:AtomicBC{T}}
293-
s = size(u)
294-
if dim == 1
295-
lower = zeros(T, s[2])
296-
upper = deepcopy(lower)
297-
for i in 1:(s[2])
298-
tmp = A[i]*u[:,i]
299-
lower[i], upper[i] = (tmp.l, tmp.r)
300-
end
301-
elseif dim == 2
302-
lower = zeros(T, s[1])
303-
upper = deepcopy(lower)
304-
for i in 1:(s[1])
305-
tmp = A[i]*u[i,:]
306-
lower[i], upper[i] = (tmp.l, tmp.r)
307-
end
308-
elseif dim == 3
309-
throw("The 3 dimensional Method should be being called, not this one. Check dispatch.")
310-
else
311-
throw("Dim greater than 3 not supported!")
312-
end
313-
return lower, upper
314-
end
315-
316-
317-
@inline function slicemul(A::Array{B,2}, u::AbstractArray{T, 3}, dim::Integer) where {T, B<:AtomicBC{T}}
318-
s = size(u)
319-
if dim == 1
320-
lower = zeros(T, s[2], s[3])
321-
upper = deepcopy(lower)
322-
for j in 1:s[3]
323-
for i in 1:s[2]
324-
tmp = A[i,j]*u[:,i,j]
325-
lower[i,j], upper[i,j] = (tmp.l, tmp.r)
326-
end
327-
end
328-
elseif dim == 2
329-
lower = zeros(T, s[1], s[3])
330-
upper = deepcopy(lower)
331-
for j in 1:s[3]
332-
for i in 1:s[1]
333-
tmp = A[i,j]*u[i,:,j]
334-
lower[i,j], upper[i,j] = (tmp.l, tmp.r)
335-
end
336-
end
337-
elseif dim == 3
338-
lower = zeros(T, s[1], s[2])
339-
upper = deepcopy(lower)
340-
for j in 1:s[2]
341-
for i in 1:s[1]
342-
tmp = A[i,j]*u[i,j,:]
343-
lower[i,j], upper[i,j] = (tmp.l, tmp.r)
344-
end
345-
end
346-
else
347-
throw("Dim greater than 3 not supported!")
348-
end
349-
return lower, upper
350-
end
351-
352-
353-
struct MultiDimDirectionalBC{T<:Number, B<:AtomicBC{T}, D, N, M} <: MultiDimensionalBC{T, N}
354-
BCs::Array{B,M} #dimension M=N-1 array of BCs to extend dimension D
355-
end
356-
357-
struct ComposedMultiDimBC{T, B<:AtomicBC{T}, N,M} <: MultiDimensionalBC{T, N}
358-
BCs::Vector{Array{B, M}}
359-
end
360-
361-
"""
362-
A multiple dimensional BC, supporting arbitrary BCs at each boundary point.
363-
To construct an arbitrary BC, pass an Array of BCs with dimension one less than that of your domain u - denoted N,
364-
with a size of size(u)[setdiff(1:N, dim)], where dim is the dimension orthogonal to the boundary that you want to extend.
365-
366-
It is also possible to call
367-
Q_dim = MultiDimBC(YourBC, size(u), dim)
368-
to use YourBC for the whole boundary orthogonal to that dimension.
369-
370-
Further, it is possible to call
371-
Qx, Qy, Qz... = MultiDimBC(YourBC, size(u))
372-
to use YourBC for the whole boundary for all dimensions. Valid for any number of dimensions greater than 1.
373-
However this is only valid for Robin/General type BCs (including neummann/dirichlet) when the grid steps are equal in each dimension - including uniform grid case.
374-
375-
In the case where you want to extend the same Robin/GeneralBC to the whole boundary with a non unifrom grid, please use
376-
Qx, Qy, Qz... = RobinBC(l, r, (dx::Vector, dy::Vector, dz::Vector ...), approximation_order, size(u))
377-
or
378-
Qx, Qy, Qz... = GeneralBC(αl, αr, (dx::Vector, dy::Vector, dz::Vector ...), approximation_order, size(u))
379-
380-
where dx, dy, and dz are vectors of grid steps.
381-
"""
382-
MultiDimBC(BC::Array{B,N}, dim::Integer) where {N, B} = MultiDimDirectionalBC{gettype(BC[1]), B, dim, N+1, N}(BC)
383-
#s should be size of the domain
384-
MultiDimBC(BC::B, s, dim::Integer) where {B} = MultiDimDirectionalBC{gettype(BC), B, dim, length(s), length(s)-1}(fill(BC, s[setdiff(1:length(s), dim)]))
385-
386-
#Extra constructor to make a set of BC operators that extend an atomic BC Operator to the whole domain
387-
#Only valid in the uniform grid case!
388-
MultiDimBC(BC::B, s) where {B} = Tuple([MultiDimDirectionalBC{gettype(BC), B, dim, length(s), length(s)-1}(fill(BC, s[setdiff(1:length(s), dim)])) for dim in 1:length(s)])
389-
390-
# Additional constructors for cases when the BC is the same for all boundarties
391-
392-
PeriodicBC{T}(s) where T = MultiDimBC(PeriodicBC{T}(), s)
393-
394-
NeumannBC::AbstractVector{T}, dxyz, order, s) where T = RobinBC([zero(T), one(T), α[1]], [zero(T), one(T), α[2]], dxyz, order, s)
395-
DirichletBC(αl::T, αr::T, s) where T = RobinBC([one(T), zero(T), αl], [one(T), zero(T), αr], [ones(T, si) for si in s], 2.0, s)
396-
397-
Dirichlet0BC(T::Type, s) = DirichletBC(zero(T), zero(T), s)
398-
Neumann0BC(T::Type, dxyz, order, s) = NeumannBC([zero(T), zero(T)], dxyz, order, s)
399-
400-
RobinBC(l::AbstractVector{T}, r::AbstractVector{T}, dxyz, order, s) where {T} = Tuple([MultiDimDirectionalBC{T, RobinBC{T}, dim, length(s), length(s)-1}(fill(RobinBC(l, r, dxyz[dim], order), s[setdiff(1:length(s), dim)])) for dim in 1:length(s)])
401-
GeneralBC(αl::AbstractVector{T}, αr::AbstractVector{T}, dxyz, order, s) where {T} = Tuple([MultiDimDirectionalBC{T, GeneralBC{T}, dim, length(s), length(s)-1}(fill(GeneralBC(αl, αr, dxyz[dim], order), s[setdiff(1:length(s), dim)])) for dim in 1:length(s)])
402-
403-
function BridgeBC(u1::AbstractArray{T,2}, dim1::Int, hilo1::String, bc1::MultiDimDirectionalBC, u2::AbstractArray{T,2}, dim2::Int, hilo2::String, bc2::MultiDimDirectionalBC) where {T}
404-
@assert 1 dim1 2 "dim1 must be 1≤dim1≤2, got dim1 = $dim1"
405-
@assert 1 dim1 2 "dim2 must be 1≤dim1≤2, got dim1 = $dim1"
406-
s1 = perpsize(u1, dim1) #
407-
s2 = perpsize(u2, dim2)
408-
@assert s1 == s2 "Arrays must be same size along boundary to be joined, got boundary sizes u1 = $s1, u2 = $s2"
409-
if hilo1 == "low"
410-
view1 = selectdim(u1, dim1, 1)
411-
if hilo2 == "low"
412-
BC1 = Array{MixedBC{T, BridgeBC{T, 2, eltype(s1)}, getboundarytype(bc1)}}(undef, s1...)
413-
BC2 = Array{MixedBC{T, BridgeBC{T, 2, eltype(s2)}, getboundarytype(bc2)}}(undef, s2...)
414-
view2 = selectdim(u2, dim2, 1)
415-
for i in 1:s1[1]
416-
BC1[i] = MixedBC(BridgeBC{T, 2, eltype(s1)}(zeros(T, 1), view(view2, i), zeros(T, 1), view(view2, i)), bc1.BCs[i])
417-
BC2[i] = MixedBC(BridgeBC{T, 2, eltype(s1)}(zeros(T, 1), view(view1, i), zeros(T, 1), view(view1, i)), bc2.BCs[i])
418-
end
419-
elseif hilo2 == "high"
420-
BC1 = Array{MixedBC{T, BridgeBC{T, 2, eltype(s1)}, getboundarytype(bc1)}}(undef, s1...)
421-
BC2 = Array{MixedBC{T, getboundarytype(bc2), BridgeBC{T, 2, eltype(s2)}}}(undef, s2...)
422-
view2 = selectdim(u2, dim2, size(u2)[dim2])
423-
for i in 1:s1[1]
424-
BC1[i] = MixedBC(BridgeBC{T, 2, eltype(s1)}(zeros(T, 1), view(view2, i), zeros(T, 1), view(view2, i)), bc1.BCs[i])
425-
BC2[i] = MixedBC(bc2.BCs[i], BridgeBC{T, 2, eltype(s1)}(zeros(T, 1), view(view1, i), zeros(T, 1), view(view1, i)))
426-
end
427-
else
428-
throw("hilo2 not recognized, please use \"high\" to connect u1 to u2 along the upper index of dim2 of u2 or \"low\" to connect along the lower index end")
429-
end
430-
elseif hilo1 == "high"
431-
view1 = selectdim(u1, dim1, size(u1)[dim1])
432-
if hilo2 == "low"
433-
BC1 = Array{MixedBC{T, getboundarytype(bc1), BridgeBC{T, 2, eltype(s1)}}}(undef, s1...)
434-
BC2 = Array{MixedBC{T, BridgeBC{T, 2, eltype(s2)}, getboundarytype(bc2)}}(undef, s2...)
435-
view2 = selectdim(u2, dim2, 1)
436-
for i in 1:s1[1]
437-
BC1[i] = MixedBC(bc1.BCs[i], BridgeBC{T, 2, eltype(s1)}(zeros(T, 1), view(view2, i), zeros(T, 1), view(view2, i)))
438-
BC2[i] = MixedBC(BridgeBC{T, 2, eltype(s1)}(zeros(T, 1), view(view1, i), zeros(T, 1), view(view1, i)), bc2.BCs[i])
439-
end
440-
elseif hilo2 == "high"
441-
BC1 = Array{MixedBC{T, getboundarytype(bc1), BridgeBC{T, 2, eltype(s1)}}}(undef, s1...)
442-
BC2 = Array{MixedBC{T, getboundarytype(bc2), BridgeBC{T, 2, eltype(s2)}}}(undef, s2...)
443-
view2 = selectdim(u2, dim2, size(u2)[dim2])
444-
for i in 1:s1[1]
445-
BC1[i] = MixedBC(bc1.BCs[i], BridgeBC{T, 2, eltype(s1)}(zeros(T, 1), view(view2, i), zeros(T, 1), view(view2, i)))
446-
BC2[i] = MixedBC(bc2.BCs[i], BridgeBC{T, 2, eltype(s1)}(zeros(T, 1), view(view1, i), zeros(T, 1), view(view1, i)))
447-
end
448-
else
449-
throw("hilo2 not recognized, please use \"high\" to connect u1 to u2 along the upper index of dim2 of u2 or \"low\" to connect along the lower index end")
450-
end
451-
else
452-
throw("hilo1 not recognized, please use \"high\" to connect u1 to u2 along the upper index of dim1 of u1 or \"low\" to connect along the lower index end")
453-
end
454-
return (MultiDimBC(BC1, dim1), MultiDimBC(BC2, dim2))
455-
end
456-
457-
function BridgeBC(u1::AbstractArray{T,3}, dim1::Int, hilo1::String, bc1::MultiDimDirectionalBC, u2::AbstractArray{T,3}, dim2::Int, hilo2::String, bc2::MultiDimDirectionalBC) where {T}
458-
@assert 1 dim1 3 "dim1 must be 1≤dim1≤3, got dim1 = $dim1"
459-
@assert 1 dim1 3 "dim2 must be 1≤dim1≤3, got dim1 = $dim1"
460-
s1 = perpsize(u1, dim1) #
461-
s2 = perpsize(u2, dim2)
462-
@assert s1 == s2 "Arrays must be same size along boundary to be joined, got boundary sizes u1 = $s1, u2 = $s2"
463-
if hilo1 == "low"
464-
view1 = selectdim(u1, dim1, 1)
465-
if hilo2 == "low"
466-
BC1 = Array{MixedBC{T, BridgeBC{T, 3, eltype(s1)}, getboundarytype(bc1)}}(undef, s1...)
467-
BC2 = Array{MixedBC{T, BridgeBC{T, 3, eltype(s2)}, getboundarytype(bc2)}}(undef, s2...)
468-
view2 = selectdim(u2, dim2, 1)
469-
for j in 1:s1[2], i in 1:s1[1]
470-
BC1[i, j] = MixedBC(BridgeBC{T, N, eltype(s1)}(zeros(T, 1), view(view2, i, j), zeros(T, 1), view(view2, i, j)), bc1.BCs[i,j])
471-
BC2[i, j] = MixedBC(BridgeBC{T, N, eltype(s1)}(zeros(T, 1), view(view1, i, j), zeros(T, 1), view(view1, i, j)), bc2.BCs[i,j])
472-
end
473-
elseif hilo2 == "high"
474-
BC1 = Array{MixedBC{T, BridgeBC{T, 3, eltype(s1)}, getboundarytype(bc1)}}(undef, s1...)
475-
BC2 = Array{MixedBC{T, getboundarytype(bc2), BridgeBC{T, 3, eltype(s2)}}}(undef, s2...)
476-
view2 = selectdim(u2, dim2, size(u2)[dim2])
477-
for j in 1:s1[2], i in 1:s1[1]
478-
BC1[i, j] = MixedBC(BridgeBC{T, N, eltype(s1)}(zeros(T, 1), view(view2, i, j), zeros(T, 1), view(view2, i, j)), bc1.BCs[i,j])
479-
BC2[i, j] = MixedBC(bc2.BCs[i,j], BridgeBC{T, N, eltype(s1)}(zeros(T, 1), view(view1, i, j), zeros(T, 1), view(view1, i, j)))
480-
end
481-
else
482-
throw("hilo2 not recognized, please use \"high\" to connect u1 to u2 along the upper index of dim2 of u2 or \"low\" to connect along the lower index end")
483-
end
484-
elseif hilo1 == "high"
485-
view1 = selectdim(u1, dim1, size(u1)[dim1])
486-
if hilo2 == "low"
487-
BC1 = Array{MixedBC{T, getboundarytype(bc1), BridgeBC{T, 3, eltype(s1)}}}(undef, s1...)
488-
BC2 = Array{MixedBC{T, BridgeBC{T, 3, eltype(s2)}, getboundarytype(bc2)}}(undef, s2...)
489-
view2 = selectdim(u2, dim2, 1)
490-
view2 = selectdim(u2, dim2, 1)
491-
for j in 1:s1[2], i in 1:s1[1]
492-
BC1[i, j] = MixedBC(bc1.BCs[i,j], BridgeBC{T, N, eltype(s1)}(zeros(T, 1), view(view2, i, j), zeros(T, 1), view(view2, i, j)))
493-
BC2[i, j] = MixedBC(BridgeBC{T, N, eltype(s1)}(zeros(T, 1), view(view1, i, j), zeros(T, 1), view(view1, i, j)), bc2.BCs[i,j])
494-
end
495-
elseif hilo2 == "high"
496-
BC1 = Array{MixedBC{T, getboundarytype(bc1), BridgeBC{T, 3, eltype(s1)}}}(undef, s1...)
497-
BC2 = Array{MixedBC{T, getboundarytype(bc2), BridgeBC{T, 3, eltype(s2)}}}(undef, s2...)
498-
view2 = selectdim(u2, dim2, size(u2)[dim2])
499-
for j in 1:s1[2], i in 1:s1[1]
500-
BC1[i, j] = MixedBC(bc1.BCs[i,j], BridgeBC{T, N, eltype(s1)}(zeros(T, 1), view(view2, i, j), zeros(T, 1), view(view2, i, j)))
501-
BC2[i, j] = MixedBC(bc2.BCs[i,j], BridgeBC{T, N, eltype(s1)}(zeros(T, 1), view(view1, i, j), zeros(T, 1), view(view1, i, j)))
502-
end
503-
else
504-
throw("hilo2 not recognized, please use \"high\" to connect u1 to u2 along the upper index of dim2 of u2 or \"low\" to connect along the lower index end")
505-
end
506-
else
507-
throw("hilo1 not recognized, please use \"high\" to connect u1 to u2 along the upper index of dim1 of u1 or \"low\" to connect along the lower index end")
508-
end
509-
return (MultiDimBC(BC1, dim1), MultiDimBC(BC2, dim2))
510-
end
511-
"""
512-
Q = compose(BCs...)
513-
514-
-------------------------------------------------------------------------------------
515-
516-
Example:
517-
Q = compose(Qx, Qy, Qz) # 3D domain
518-
Q = compose(Qx, Qy) # 2D Domain
519-
520-
Creates a ComposedMultiDimBC operator, Q, that extends every boundary when applied to a `u` with compatible size and number of dimensions.
521-
522-
Qx Qy and Qz can be passed in any order, as long as there is exactly one BC operator that extends each dimension.
523-
"""
524-
function compose(BCs...)
525-
T = gettype(BCs[1])
526-
N = ndims(BCs[1])
527-
Ds = getaxis.(BCs)
528-
(length(BCs) == N) || throw("There must be enough BCs to cover every dimension - check that the number of MultiDimBCs == N")
529-
for D in Ds
530-
length(setdiff(Ds, D)) == (N-1) || throw("There are multiple boundary conditions that extend along $D - make sure every dimension has a unique extension")
531-
end
532-
BCs = BCs[sortperm([Ds...])]
533-
534-
ComposedMultiDimBC{T, Union{eltype.(BCs)...}, N,N-1}([condition.BC for condition in BCs])
535-
end
536-
537-
"""
538-
Qx, Qy,... = decompose(Q::ComposedMultiDimBC{T,N,M})
539-
540-
-------------------------------------------------------------------------------------
541-
542-
Decomposes a ComposedMultiDimBC in to components that extend along each dimension individually
543-
"""
544-
decompose(Q::ComposedMultiDimBC) = Tuple([MultiDimBC(Q.BC[i], i) for i in 1:ndims(Q)])
545-
546-
getaxis(Q::MultiDimDirectionalBC{T, B, D, N, K}) where {T, B, D, N, K} = D
547-
getboundarytype(Q::MultiDimDirectionalBC{T, B, D, N, K}) where {T, B, D, N, K} = B
548-
549-
Base.ndims(Q::MultiDimensionalBC{T,N}) where {T,N} = N
550-
551-
function Base.:*(Q::MultiDimDirectionalBC{T, B, D, N, K}, u::AbstractArray{T, N}) where {T, B, D, N, K}
552-
lower, upper = slicemul(Q.BCs, u, D)
553-
return BoundaryPaddedArray{T, D, N, K, typeof(u), typeof(lower)}(lower, upper, u)
554-
end
555-
556-
function Base.:*(Q::ComposedMultiDimBC{T, B, N, K}, u::AbstractArray{T, N}) where {T, B, N, K}
557-
out = slicemul.(Q.BCs, fill(u, N), 1:N)
558-
return ComposedBoundaryPaddedArray{T, N, K, typeof(u), typeof(out[1][1])}([A[1] for A in out], [A[2] for A in out], u)
559-
end

0 commit comments

Comments
 (0)