changeset 286:7247e85dc1e8 tensor_mappings

Start separating ConstantStencilOp into multiple 1D tensor mappings, e.g. ConstantLaplaceOp. Sketch an implementation of the multi-D laplace tensor operator as a tuple of 1D laplace tensor operators.
author Vidar Stiernström <vidar.stiernstrom@it.uu.se>
date Mon, 22 Jun 2020 19:47:20 +0200
parents e21dcda55163
children dd621017b695
files DiffOps/src/laplace.jl SbpOperators/src/constantlaplace.jl
diffstat 2 files changed, 70 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/DiffOps/src/laplace.jl	Fri Jun 19 12:20:31 2020 +0200
+++ b/DiffOps/src/laplace.jl	Mon Jun 22 19:47:20 2020 +0200
@@ -1,13 +1,18 @@
+#TODO: move to sbpoperators.jl
+"""
+    Laplace{Dim,T<:Real,N,M,K} <: TensorOperator{T,Dim}
+
+Implements the Laplace operator `L` in Dim dimensions as a tensor operator
+The multi-dimensional tensor operator simply consists of a tuple of the 1D
+Laplace tensor operator as defined by ConstantLaplaceOperator.
+"""
 struct Laplace{Dim,T<:Real,N,M,K} <: TensorOperator{T,Dim}
-    grid::EquidistantGrid{Dim,T}  # TODO: Should this be here? Should probably be possible to applay a Laplace object to any size grid function
-    a::T # TODO: Better name?
-    op::D2{T,N,M,K}
+    tensorOps::NTuple(Dim,ConstantLaplaceOperator{T,N,M,K})
+    #TODO: Write a good constructor
 end
 export Laplace
 
-# At the moment the grid property is used all over. It could possibly be removed if we implement all the 1D operators as TensorMappings
-
-LazyTensors.domain_size(H::Laplace{Dim}, range_size::NTuple{Dim,Integer}) where Dim = range_size
+LazyTensors.domain_size(H::Laplace{Dim}, range_size::NTuple{Dim,Integer}) = range_size
 
 function LazyTensors.apply(L::Laplace{Dim,T}, v::AbstractArray{T,Dim}, I::NTuple{Dim,Index}) where {T,Dim}
     error("not implemented")
@@ -15,18 +20,19 @@
 
 # u = L*v
 function LazyTensors.apply(L::Laplace{1,T}, v::AbstractVector{T}, I::NTuple{1,Index}) where T
-    uᵢ = L.a*apply_2nd_derivative(L.op, inverse_spacing(L.grid)[1], v, I[1])
-    return uᵢ
+    return apply(L.tensorOps[1],v,I)
 end
 
 
 @inline function LazyTensors.apply(L::Laplace{2,T}, v::AbstractArray{T,2}, I::NTuple{2,Index}) where T
     # 2nd x-derivative
     @inbounds vx = view(v, :, Int(I[2]))
-    @inbounds uᵢ = L.a*apply_2nd_derivative(L.op, inverse_spacing(L.grid)[1], vx , I[1])
+    @inbounds uᵢ = apply(L.tensorOps[1], vx , (I[1],)) #Tuple conversion here is ugly. How to do it? Should we use indexing here?
+
     # 2nd y-derivative
     @inbounds vy = view(v, Int(I[1]), :)
-    @inbounds uᵢ += L.a*apply_2nd_derivative(L.op, inverse_spacing(L.grid)[2], vy, I[2])
+    @inbounds uᵢ += apply(L.tensorOps[2], vy , (I[2],)) #Tuple conversion here is ugly. How to do it?
+
     return uᵢ
 end
 
@@ -37,6 +43,7 @@
 boundary_quadrature(L::Laplace, bId::CartesianBoundary) = BoundaryQuadrature(L.op, L.grid, bId)
 export quadrature
 
+# At the moment the grid property is used all over. It could possibly be removed if we implement all the 1D operators as TensorMappings
 """
     Quadrature{Dim,T<:Real,N,M,K} <: TensorMapping{T,Dim,Dim}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SbpOperators/src/constantlaplace.jl	Mon Jun 22 19:47:20 2020 +0200
@@ -0,0 +1,53 @@
+#TODO: Naming?! What is this? It is a 1D tensor operator but what is then the
+# potentially multi-D laplace tensor mapping then?
+# Ideally I would like the below to be the laplace operator in 1D, while the
+# multi-D operator is a a tuple of the 1D-operator. Possible via recursive
+# definitions? Or just bad design?
+"""
+    ConstantLaplaceOperator{T<:Real,N,M,K} <: TensorOperator{T,1}
+Implements the Laplace tensor operator `L` with constant grid spacing and coefficients
+in 1D dimension
+"""
+struct ConstantLaplaceOperator{T<:Real,N,M,K} <: TensorOperator{T,1}
+    h_inv::T # The grid spacing could be included in the stencil already. Preferable?
+    a::T # TODO: Better name?
+    innerStencil::Stencil{T,N}
+    closureStencils::NTuple{M,Stencil{T,K}}
+    parity::Parity
+end
+
+@enum Parity begin
+    odd = -1
+    even = 1
+end
+
+LazyTensors.domain_size(L::ConstantLaplaceOperator, range_size::NTuple{1,Integer}) = range_size
+
+function LazyTensors.apply(L::ConstantLaplaceOperator{T}, v::AbstractVector{T}, I::NTuple{1,Index}) where T
+    return L.a*apply_2nd_derivative(L, L.h_inv, v, I[1])
+end
+
+# Apply for different regions Lower/Interior/Upper or Unknown region
+@inline function apply_2nd_derivative(L::ConstantLaplaceOperator, h_inv::Real, v::AbstractVector, i::Index{Lower})
+    return @inbounds h_inv*h_inv*apply_stencil(L.closureStencils[Int(i)], v, Int(i))
+end
+
+@inline function apply_2nd_derivative(L::ConstantLaplaceOperator, h_inv::Real, v::AbstractVector, i::Index{Interior})
+    return @inbounds h_inv*h_inv*apply_stencil(L.innerStencil, v, Int(i))
+end
+
+@inline function apply_2nd_derivative(L::ConstantLaplaceOperator, h_inv::Real, v::AbstractVector, i::Index{Upper})
+    N = length(v) # Can we use range_size here instead?
+    return @inbounds h_inv*h_inv*Int(L.parity)*apply_stencil_backwards(L.closureStencils[N-Int(i)+1], v, Int(i))
+end
+
+@inline function apply_2nd_derivative(L::ConstantLaplaceOperator, h_inv::Real, v::AbstractVector, index::Index{Unknown})
+    N = length(v) # Can we use range_size here instead?
+    r = getregion(Int(index), closuresize(L), N)
+    i = Index(Int(index), r)
+    return apply_2nd_derivative(op, h_inv, v, i)
+end
+
+function closuresize(L::ConstantLaplaceOperator{T<:Real,N,M,K})::Int
+    return M
+end