Mercurial > repos > public > sbplib_julia
diff src/SbpOperators/volumeops/laplace/laplace.jl @ 875:067a322e4f73 laplace_benchmarks
Merge with feature/laplace_opset
author | Vidar Stiernström <vidar.stiernstrom@it.uu.se> |
---|---|
date | Thu, 27 Jan 2022 10:55:08 +0100 |
parents | 9929c99754fb 86776d06b883 |
children |
line wrap: on
line diff
--- a/src/SbpOperators/volumeops/laplace/laplace.jl Thu Jan 20 21:51:53 2022 +0100 +++ b/src/SbpOperators/volumeops/laplace/laplace.jl Thu Jan 27 10:55:08 2022 +0100 @@ -1,19 +1,39 @@ +export Laplace +export laplace +# REVIEW: Makes more sense to me to have the exports at the top of the file. +# Might as well start fixing that. + +# REVIEW: The style of name `Laplace` might clash with other concepts. When +# thinking about implementing the variable second derivative I think I will +# have to create it as a full TM for the full dimensional problem instead of +# building it as a 1D operator and then use that with outer products. The +# natural name there would be `VariableSecondDerivative` (or something +# similar). But the similarity of the two names would suggest that `Laplace` +# and `VariableSecondDerivative` are the same kind of thing, which they +# wouldn't be. +# +# How do we distinguish the kind of type we are implementing here and what we +# could potentially do for the variable second derivative? +# +# I see two ways out: +# * Come up with a name for these sets of operators and change `Laplace` accordingly. +# * Come up with a name for the bare operators and change `VariableSecondDerivative` accordingly. + """ Laplace{T, Dim, TMdiffop} <: TensorMapping{T,Dim,Dim} - Laplace(grid::AbstractGrid, fn; order) + Laplace(grid, filename; order) Implements the Laplace operator, approximating ∑d²/xᵢ² , i = 1,...,`Dim` as a `TensorMapping`. Additionally, `Laplace` stores the inner product and boundary -operators relevant for constructing a SBP finite difference scheme as `TensorMapping`s. +operators relevant for constructing a SBP finite difference scheme as a `TensorMapping`. -Laplace(grid, fn; order) creates the Laplace operator defined on `grid`, +`Laplace(grid, filename; order)` creates the Laplace operator defined on `grid`, where the operators are read from TOML. The differential operator is created -using `laplace(grid::AbstractGrid,...)`. +using `laplace(grid,...)`. -Note that all properties of Laplace, excluding the Differential operator `D`, are +Note that all properties of Laplace, excluding the differential operator `Laplace.D`, are abstract types. For performance reasons, they should therefore be accessed via the provided getter functions (e.g `inner_product(::Laplace)`). - """ struct Laplace{T, Dim, TMdiffop<:TensorMapping{T,Dim,Dim}} <: TensorMapping{T,Dim,Dim} D::TMdiffop # Differential operator @@ -21,39 +41,41 @@ H_inv::TensorMapping # Inverse inner product operator e::StaticDict{<:BoundaryIdentifier,<:TensorMapping} # Boundary restriction operators. d::StaticDict{<:BoundaryIdentifier,<:TensorMapping} # Normal derivative operators - H_boundary::StaticDict{<:BoundaryIdentifier,<:TensorMapping} # Boundary quadrature operators # TODO: Boundary inner product? - order::Int + H_boundary::StaticDict{<:BoundaryIdentifier,<:TensorMapping} # Boundary quadrature operators end -export Laplace -function Laplace(grid::AbstractGrid, fn; order) +function Laplace(grid, filename; order) + + # Read stencils + stencil_set = read_stencil_set(filename; order) # TODO: Removed once we can construct the volume and - # boundary operators by op(grid, fn; order,...). - # Read stencils - op = read_D2_operator(fn; order) - D_inner_stecil = op.innerStencil - D_closure_stencils = op.closureStencils - H_closure_stencils = op.quadratureClosure - e_closure_stencil = op.eClosure - d_closure_stencil = op.dClosure + # boundary operators by op(grid, read_stencil_set(fn; order,...)). + D_inner_stecil = parse_stencil(stencil_set["D2"]["inner_stencil"]) + D_closure_stencils = parse_stencil.(stencil_set["D2"]["closure_stencils"]) + H_inner_stencils = parse_scalar(stencil_set["H"]["inner"]) + H_closure_stencils = parse_tuple(stencil_set["H"]["closure"]) + e_closure_stencil = parse_stencil(stencil_set["e"]["closure"]) + d_closure_stencil = parse_stencil(stencil_set["d1"]["closure"]) + # REVIEW: Do we add the methods to get rid of this in this branch or a new one? # Volume operators Δ = laplace(grid, D_inner_stecil, D_closure_stencils) - H = inner_product(grid, H_closure_stencils) - H⁻¹ = inverse_inner_product(grid, H_closure_stencils) + H = inner_product(grid, H_inner_stencils, H_closure_stencils) + H⁻¹ = inverse_inner_product(grid, H_inner_stencils, H_closure_stencils) # Boundary operator - id pairs ids = boundary_identifiers(grid) - n_ids = length(ids) - e_pairs = ntuple(i -> ids[i] => boundary_restriction(grid,e_closure_stencil,ids[i]),n_ids) - d_pairs = ntuple(i -> ids[i] => normal_derivative(grid,d_closure_stencil,ids[i]),n_ids) - Hᵧ_pairs = ntuple(i -> ids[i] => inner_product(boundary_grid(grid,ids[i]),H_closure_stencils),n_ids) + # REVIEW: Change suggestion: Seems more readable to me but pretty subjective so feel free to ignore + e_pairs = map(id -> Pair(id, boundary_restriction(grid, e_closure_stencil, id)), ids) + d_pairs = map(id -> Pair(id, normal_derivative(grid, d_closure_stencil, id)), ids) + Hᵧ_pairs = map(id -> Pair(id, inner_product(boundary_grid(grid, id), H_inner_stencils, H_closure_stencils)), ids) return Laplace(Δ, H, H⁻¹, StaticDict(e_pairs), StaticDict(d_pairs), StaticDict(Hᵧ_pairs), order) end # TODO: Consider pretty printing of the following form # Base.show(io::IO, L::Laplace{T, Dim}) where {T,Dim,TM} = print(io, "Laplace{$T, $Dim, $TM}(", L.D, L.H, L.H_inv, L.e, L.d, L.H_boundary, ")") +# REVIEW: Should leave a todo here to update this once we have some pretty printing for tensor mappings in general. LazyTensors.range_size(L::Laplace) = LazyTensors.range_size(L.D) LazyTensors.domain_size(L::Laplace) = LazyTensors.domain_size(L.D) @@ -69,69 +91,65 @@ export closure_size """ - inner_product(L::Lapalace) + inner_product(L::Laplace) Returns the inner product operator associated with `L` - """ inner_product(L::Laplace) = L.H -export inner_product """ - inverse_inner_product(L::Lapalace) + inverse_inner_product(L::Laplace) Returns the inverse of the inner product operator associated with `L` - """ inverse_inner_product(L::Laplace) = L.H_inv -export inverse_inner_product """ - boundary_restriction(L::Lapalace,id::BoundaryIdentifier) - boundary_restriction(L::Lapalace,ids::NTuple{N,BoundaryIdentifier}) - boundary_restriction(L::Lapalace,ids...) + boundary_restriction(L::Laplace, id::BoundaryIdentifier) + boundary_restriction(L::Laplace, ids::Tuple) + boundary_restriction(L::Laplace, ids...) Returns boundary restriction operator(s) associated with `L` for the boundary(s) identified by id(s). +""" +boundary_restriction(L::Laplace, id::BoundaryIdentifier) = L.e[id] +boundary_restriction(L::Laplace, ids::Tuple) = map(id-> L.e[id], ids) +boundary_restriction(L::Laplace, ids...) = boundary_restriction(L, ids) +# REVIEW: I propose changing the following implementations according to the +# above. There are some things we're missing with regards to +# `BoundaryIdentifier`, for example we should be able to handle groups of +# boundaries as a single `BoundaryIdentifier`. I don't know if we can figure +# out the interface for that now or if we save it for the future but either +# way these methods will be affected. -""" -boundary_restriction(L::Laplace,id::BoundaryIdentifier) = L.e[id] -boundary_restriction(L::Laplace,ids::NTuple{N,BoundaryIdentifier}) where N = ntuple(i->L.e[ids[i]],N) -boundary_restriction(L::Laplace,ids::Vararg{BoundaryIdentifier,N}) where N = ntuple(i->L.e[ids[i]],N) -export boundary_restriction """ - normal_derivative(L::Lapalace,id::BoundaryIdentifier) - normal_derivative(L::Lapalace,ids::NTuple{N,BoundaryIdentifier}) - normal_derivative(L::Lapalace,ids...) + normal_derivative(L::Laplace, id::BoundaryIdentifier) + normal_derivative(L::Laplace, ids::NTuple{N,BoundaryIdentifier}) + normal_derivative(L::Laplace, ids...) Returns normal derivative operator(s) associated with `L` for the boundary(s) identified by id(s). +""" +normal_derivative(L::Laplace, id::BoundaryIdentifier) = L.d[id] +normal_derivative(L::Laplace, ids::NTuple{N,BoundaryIdentifier}) where N = ntuple(i->L.d[ids[i]],N) +normal_derivative(L::Laplace, ids::Vararg{BoundaryIdentifier,N}) where N = ntuple(i->L.d[ids[i]],N) + """ -normal_derivative(L::Laplace,id::BoundaryIdentifier) = L.d[id] -normal_derivative(L::Laplace,ids::NTuple{N,BoundaryIdentifier}) where N = ntuple(i->L.d[ids[i]],N) -normal_derivative(L::Laplace,ids::Vararg{BoundaryIdentifier,N}) where N = ntuple(i->L.d[ids[i]],N) -export normal_derivative - - -# TODO: boundary_inner_product? -""" - boundary_quadrature(L::Lapalace,id::BoundaryIdentifier) - boundary_quadrature(L::Lapalace,ids::NTuple{N,BoundaryIdentifier}) - boundary_quadrature(L::Lapalace,ids...) + boundary_quadrature(L::Laplace, id::BoundaryIdentifier) + boundary_quadrature(L::Laplace, ids::NTuple{N,BoundaryIdentifier}) + boundary_quadrature(L::Laplace, ids...) Returns boundary quadrature operator(s) associated with `L` for the boundary(s) identified by id(s). - """ -boundary_quadrature(L::Laplace,id::BoundaryIdentifier) = L.H_boundary[id] -boundary_quadrature(L::Laplace,ids::NTuple{N,BoundaryIdentifier}) where N = ntuple(i->L.H_boundary[ids[i]],N) -boundary_quadrature(L::Laplace,ids::Vararg{BoundaryIdentifier,N}) where N = ntuple(i->L.H_boundary[ids[i]],N) -export boundary_quadrature +boundary_quadrature(L::Laplace, id::BoundaryIdentifier) = L.H_boundary[id] +boundary_quadrature(L::Laplace, ids::NTuple{N,BoundaryIdentifier}) where N = ntuple(i->L.H_boundary[ids[i]],N) +boundary_quadrature(L::Laplace, ids::Vararg{BoundaryIdentifier,N}) where N = ntuple(i->L.H_boundary[ids[i]],N) abstract type BoundaryConditionType end struct NeumannBC <: BoundaryConditionType end @@ -153,53 +171,23 @@ return closure end -function dirichlet_bc(L::Laplace, id::BoundaryIdentifier) - error("Not implemented") - # H_inv = inverse_inner_product(L) - # e = boundary_restriction(L,id) - # d = normal_derivative(L,id) - # H_b = boundary_quadrature(L,id) - # gamma = borrowing_parameter(L) - # tuning = 1.2 - # S = ScalingOperator(tuning * -1.0/gamma) - # tau = H_inv∘(S∘e' + d')∘H_b - # closure = tau∘e - # penalty = ScalingOperator(-1)∘tau - # return (closure, penalty) -end - -# function borrowing_parameter(L) -# if L.order == 2 -# return 0.4 -# elseif L.order == 4 -# return 0.2508 -# elseif L.order == 6 -# return 0.1878 -# elseif L.order == 8 -# return 0.0015 -# elseif L.order == 10 -# return 0.0351 -# end -# end - """ - laplace(grid, inner_stencil, closure_stencils) + laplace(grid::EquidistantGrid{Dim}, inner_stencil, closure_stencils) Creates the Laplace operator operator `Δ` as a `TensorMapping` -`Δ` approximates the Laplace operator ∑d²/xᵢ² , i = 1,...,N on the N-dimensional -`grid`, using the stencil `inner_stencil` in the interior and a set of stencils -`closure_stencils` for the points in the closure regions. +`Δ` approximates the Laplace operator ∑d²/xᵢ² , i = 1,...,`Dim` on `grid`, using +the stencil `inner_stencil` in the interior and a set of stencils `closure_stencils` +for the points in the closure regions. On a one-dimensional `grid`, `Δ` is equivalent to `second_derivative`. On a multi-dimensional `grid`, `Δ` is the sum of multi-dimensional `second_derivative`s where the sum is carried out lazily. """ -function laplace(grid::AbstractGrid, inner_stencil, closure_stencils) +function laplace(grid::EquidistantGrid, inner_stencil, closure_stencils) Δ = second_derivative(grid, inner_stencil, closure_stencils, 1) for d = 2:dimension(grid) Δ += second_derivative(grid, inner_stencil, closure_stencils, d) end return Δ end -export laplace