Skip to content

Commit 8745f01

Browse files
committed
further extension of new interpolator structures (MomentInterpolator now also used for interior Hdiv dofs, new FluxEvaluator evaluates normal/tangential fluxes for Hdiv/Hcurl boundary dofs)
1 parent 7b2d655 commit 8745f01

8 files changed

Lines changed: 353 additions & 417 deletions

File tree

src/fedefs/hcurl_n0.jl

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,41 +38,38 @@ isdefined(FEType::Type{<:HCURLN0}, ::Type{<:Triangle2D}) = true
3838
isdefined(FEType::Type{<:HCURLN0}, ::Type{<:Quadrilateral2D}) = true
3939
isdefined(FEType::Type{<:HCURLN0}, ::Type{<:Tetrahedron3D}) = true
4040

41-
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_EDGES}, data; items = [], kwargs...) where {T, Tv, Ti, FEType <: HCURLN0, APT}
41+
function N0_tangentflux_eval_2d!(result, f, qpinfo)
42+
result[1] = -f[1] * qpinfo.normal[2] # rotated normal = tangent
43+
return result[1] += f[2] * qpinfo.normal[1]
44+
end
45+
init_interpolator!(FES::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}) where {Tv, Ti, FEType <: HCURLN0{2}, APT} = FaceFluxEvaluator(N0_tangentflux_eval_2d!, FES, ON_FACES)
46+
47+
function N0_tangentflux_eval_3d!(grid)
48+
edgetangents = grid[EdgeTangents]
49+
function closure(result, f, qpinfo)
50+
result[1] = dot(f, view(edgetangents, :, qpinfo.item))
51+
end
52+
return closure
53+
end
54+
init_interpolator!(FES::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_EDGES}) where {Tv, Ti, FEType <: HCURLN0{3}, APT} = FaceFluxEvaluator(N0_tangentflux_eval_3d!(FES.dofgrid), FES, ON_EDGES)
55+
56+
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_EDGES}, exact_function!; items = [], kwargs...) where {T, Tv, Ti, FEType <: HCURLN0, APT}
4257
edim = get_ncomponents(FEType)
4358
return if edim == 3
44-
xEdgeTangents = FE.dofgrid[EdgeTangents]
45-
if items == []
46-
items = 1:size(xEdgeTangents, 2)
47-
end
48-
data_eval = zeros(T, 3)
49-
function tangentflux_eval3d(result, qpinfo)
50-
data(data_eval, qpinfo)
51-
return result[1] = dot(data_eval, view(xEdgeTangents, :, qpinfo.item))
52-
end
53-
integrate!(Target, FE.dofgrid, ON_EDGES, tangentflux_eval3d; items = items, kwargs...)
59+
get_interpolator(FE, ON_EDGES).evaluate!(Target, exact_function!, items; kwargs...)
5460
end
5561
end
5662

57-
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, data; items = [], kwargs...) where {T, Tv, Ti, FEType <: HCURLN0, APT}
63+
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, exact_function!; items = [], kwargs...) where {T, Tv, Ti, FEType <: HCURLN0, APT}
5864
edim = get_ncomponents(FEType)
59-
return if edim == 2
60-
xFaceNormals = FE.dofgrid[FaceNormals]
61-
if items == []
62-
items = 1:size(xFaceNormals, 2)
63-
end
64-
data_eval = zeros(T, 2)
65-
function tangentflux_eval2d(result, qpinfo)
66-
data(data_eval, qpinfo)
67-
result[1] = -data_eval[1] * xFaceNormals[2, qpinfo.item] # rotated normal = tangent
68-
return result[1] += data_eval[2] * xFaceNormals[1, qpinfo.item]
69-
end
70-
integrate!(Target, FE.dofgrid, ON_FACES, tangentflux_eval2d; items = items, kwargs...)
65+
if edim == 2
66+
get_interpolator(FE, ON_FACES).evaluate!(Target, exact_function!, items; kwargs...)
7167
elseif edim == 3
7268
# delegate face edges to edge interpolation
7369
subitems = slice(FE.dofgrid[FaceEdges], items)
7470
interpolate!(Target, FE, ON_EDGES, data; items = subitems, kwargs...)
7571
end
72+
return nothing
7673
end
7774

7875
function ExtendableGrids.interpolate!(Target, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_CELLS}, data; items = [], kwargs...) where {Tv, Ti, FEType <: HCURLN0, APT}

src/fedefs/hcurl_n1.jl

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,26 @@ get_dofmap_pattern(FEType::Type{<:HCURLN1{2}}, ::Union{Type{FaceDofs}, Type{BFac
2727

2828
isdefined(FEType::Type{<:HCURLN1}, ::Type{<:Triangle2D}) = true
2929

30-
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_EDGES}, data; items = [], kwargs...) where {T, Tv, Ti, FEType <: HCURLN1, APT}
30+
function N1_tangentflux_eval_2d!(result, f, qpinfo)
31+
result[1] = -f[1] * qpinfo.normal[2] # rotated normal = tangent
32+
result[1] += f[2] * qpinfo.normal[1]
33+
result[2] = result[1] * (qpinfo.xref[1] - 1 // 2)
34+
return nothing
35+
end
36+
init_interpolator!(FES::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}) where {Tv, Ti, FEType <: HCURLN1{2}, APT} = FaceFluxEvaluator(N1_tangentflux_eval_2d!, FES, ON_FACES)
37+
38+
39+
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_EDGES}, exact_function!; items = [], kwargs...) where {T, Tv, Ti, FEType <: HCURLN1, APT}
3140
edim = get_ncomponents(FEType)
3241
return if edim == 3
3342
# todo
3443
end
3544
end
3645

37-
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, data; items = [], kwargs...) where {T, Tv, Ti, FEType <: HCURLN1, APT}
46+
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, exact_function!; items = [], kwargs...) where {T, Tv, Ti, FEType <: HCURLN1, APT}
3847
edim = get_ncomponents(FEType)
3948
return if edim == 2
40-
xFaceNormals = FE.dofgrid[FaceNormals]
41-
nfaces = num_sources(xFaceNormals)
42-
if items == []
43-
items = 1:size(xFaceNormals, 2)
44-
end
45-
# integrate normal flux of exact_function over edges
46-
data_eval = zeros(T, 2)
47-
function tangentflux_eval2d(result, qpinfo)
48-
data(data_eval, qpinfo)
49-
result[1] = -data_eval[1] * xFaceNormals[2, qpinfo.item] # rotated normal = tangent
50-
result[1] += data_eval[2] * xFaceNormals[1, qpinfo.item]
51-
return result[2] = result[1] * (qpinfo.xref[1] - 1 // 2)
52-
end
53-
integrate!(Target, FE.dofgrid, ON_FACES, tangentflux_eval2d; quadorder = 2, items = items, offset = [0, nfaces], kwargs...)
49+
get_interpolator(FE, ON_FACES).evaluate!(Target, exact_function!, items; kwargs...)
5450
elseif edim == 3
5551
# delegate face edges to edge interpolation
5652
subitems = slice(FE.dofgrid[FaceEdges], items)

src/fedefs/hdiv_bdm1.jl

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,20 @@ isdefined(FEType::Type{<:HDIVBDM1}, ::Type{<:Triangle2D}) = true
4040
isdefined(FEType::Type{<:HDIVBDM1}, ::Type{<:Quadrilateral2D}) = true
4141
isdefined(FEType::Type{<:HDIVBDM1}, ::Type{<:Tetrahedron3D}) = true
4242

43-
44-
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, data; items = [], kwargs...) where {T, Tv, Ti, FEType <: HDIVBDM1, APT}
45-
ncomponents = get_ncomponents(FEType)
46-
xFaceNormals = FE.dofgrid[FaceNormals]
47-
nfaces = num_sources(xFaceNormals)
48-
if items == []
49-
items = 1:nfaces
50-
end
51-
52-
# integrate normal flux of exact_function over edges
53-
data_eval = zeros(T, ncomponents)
54-
function normalflux_eval(result, qpinfo)
55-
data(data_eval, qpinfo)
56-
result[1] = dot(data_eval, view(xFaceNormals, :, qpinfo.item))
57-
result[2] = result[1] * (qpinfo.xref[1] - 1 // ncomponents)
58-
return if ncomponents == 3
59-
result[3] = result[1] * (qpinfo.xref[2] - 1 // ncomponents)
43+
function BDM1_normalflux_eval!(dim)
44+
function closure(result, f, qpinfo)
45+
result[1] = dot(f, qpinfo.normal)
46+
result[2] = result[1] * (qpinfo.xref[1] - 1 // dim)
47+
if dim == 3
48+
result[3] = result[1] * (qpinfo.xref[2] - 1 // dim)
6049
end
6150
end
62-
return integrate!(Target, FE.dofgrid, ON_FACES, normalflux_eval; quadorder = 2, items = items, offset = 0:nfaces:((ncomponents - 1) * nfaces), kwargs...)
51+
end
52+
init_interpolator!(FES::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}) where {Tv, Ti, FEType <: HDIVBDM1, APT} = FaceFluxEvaluator(BDM1_normalflux_eval!(FEType.parameters[1]), FES, ON_FACES)
53+
54+
55+
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, exact_function!; items = [], kwargs...) where {T, Tv, Ti, FEType <: HDIVBDM1, APT}
56+
get_interpolator(FE, ON_FACES).evaluate!(Target, exact_function!, items; kwargs...)
6357
end
6458

6559
function ExtendableGrids.interpolate!(Target, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_CELLS}, data; items = [], kwargs...) where {Tv, Ti, FEType <: HDIVBDM1, APT}

src/fedefs/hdiv_bdm2.jl

Lines changed: 17 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -30,138 +30,30 @@ isdefined(FEType::Type{<:HDIVBDM2}, ::Type{<:Triangle2D}) = true
3030
interior_dofs_offset(::Type{<:ON_CELLS}, ::Type{<:HDIVBDM2{2}}, ::Type{<:Triangle2D}) = 9
3131

3232

33-
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, data; items = [], kwargs...) where {T, Tv, Ti, FEType <: HDIVBDM2, APT}
34-
ncomponents = get_ncomponents(FEType)
35-
xFaceNormals = FE.dofgrid[FaceNormals]
36-
nfaces = num_sources(xFaceNormals)
37-
if items == []
38-
items = 1:nfaces
33+
function BDM2_normalflux_eval!(dim)
34+
@assert dim == 2 "BDM3 for dim=3 not available yet"
35+
function closure(result, f, qpinfo)
36+
result[1] = dot(f, qpinfo.normal)
37+
result[2] = result[1] * (qpinfo.xref[1] - 1 // dim)
38+
result[3] = result[1] * (qpinfo.xref[1]^2 - qpinfo.xref[1] + 1 // 6)
3939
end
40+
end
41+
init_interpolator!(FES::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}) where {Tv, Ti, FEType <: HDIVBDM2, APT} = FaceFluxEvaluator(BDM2_normalflux_eval!(FEType.parameters[1]), FES, ON_FACES)
42+
init_interpolator!(FES::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_CELLS}) where {Tv, Ti, FEType <: HDIVBDM2{2}, APT} = MomentInterpolator(FES, ON_CELLS; FEType_moments = H1MINI{1,2}, moments_dofs = [1,2,4], moments_operator = CurlScalar)
4043

41-
# integrate normal flux of exact_function over edges
42-
data_eval = zeros(T, ncomponents)
43-
function normalflux_eval(result, qpinfo)
44-
data(data_eval, qpinfo)
45-
result[1] = dot(data_eval, view(xFaceNormals, :, qpinfo.item))
46-
result[2] = result[1] * (qpinfo.xref[1] - 1 // ncomponents)
47-
return result[3] = result[1] * (qpinfo.xref[1]^2 - qpinfo.xref[1] + 1 // 6)
48-
end
49-
return integrate!(Target, FE.dofgrid, ON_FACES, normalflux_eval; quadorder = 4, items = items, offset = [0, nfaces, 2 * nfaces], kwargs...)
44+
45+
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, exact_function!; items = [], kwargs...) where {T, Tv, Ti, FEType <: HDIVBDM2, APT}
46+
get_interpolator(FE, ON_FACES).evaluate!(Target, exact_function!, items; kwargs...)
5047
end
5148

52-
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_CELLS}, data; items = [], time = 0, bonus_quadorder = 0, kwargs...) where {T, Tv, Ti, FEType <: HDIVBDM2, APT}
49+
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_CELLS}, exact_function!; items = [], time = 0, bonus_quadorder = 0, kwargs...) where {T, Tv, Ti, FEType <: HDIVBDM2, APT}
5350
# delegate cell faces to face interpolation
5451
subitems = slice(FE.dofgrid[CellFaces], items)
55-
interpolate!(Target, FE, ON_FACES, data; items = subitems, kwargs...)
56-
57-
# set values of interior BDM2 functions as piecewise best-approximation
58-
ncomponents = get_ncomponents(FEType)
59-
EG = (ncomponents == 2) ? Triangle2D : Tetrahedron3D
60-
ndofs = get_ndofs(ON_CELLS, FEType, EG)
61-
interior_offset::Int = 9
62-
nidofs::Int = ndofs - interior_offset
63-
ncells = num_sources(FE.dofgrid[CellNodes])
64-
xCellVolumes::Array{Tv, 1} = FE.dofgrid[CellVolumes]
65-
xCellRegions = FE.dofgrid[CellRegions]
66-
xCellDofs::DofMapTypes{Ti} = FE[CellDofs]
67-
qf = QuadratureRule{T, EG}(max(4, 2 + bonus_quadorder))
68-
FEB = FEEvaluator(FE, Identity, qf; T = T)
69-
QP = QPInfos(FE.dofgrid; kwargs...)
70-
71-
# evaluation of gradient of P1 functions
72-
FE3 = H1P1{1}
73-
FES3 = FESpace{FE3, ON_CELLS}(FE.dofgrid)
74-
FEBP1 = FEEvaluator(FES3, Gradient, qf; T = T)
75-
# evaluation of curl of bubble functions
76-
FE4 = H1BUBBLE{1}
77-
FES4 = FESpace{FE4, ON_CELLS}(FE.dofgrid)
78-
FEBB = FEEvaluator(FES4, CurlScalar, qf; T = T)
79-
80-
if items == []
81-
items = 1:ncells
82-
end
83-
84-
interiordofs = zeros(Int, nidofs)
85-
basisvals::Array{T, 3} = FEB.cvals
86-
basisvalsP1::Array{T, 3} = FEBP1.cvals
87-
basisvalsB::Array{T, 3} = FEBB.cvals
88-
IMM_face = zeros(T, nidofs, interior_offset)
89-
IMM = zeros(T, nidofs, nidofs)
90-
lb = zeros(T, nidofs)
91-
temp::T = 0
92-
data_eval = zeros(T, ncomponents)
93-
for cell in items
94-
# update basis
95-
update_basis!(FEB, cell)
96-
update_basis!(FEBP1, cell)
97-
update_basis!(FEBB, cell)
98-
fill!(IMM, 0)
99-
fill!(IMM_face, 0)
100-
fill!(lb, 0)
101-
102-
QP.item = cell
103-
QP.cell = cell
104-
QP.region = xCellRegions[cell]
105-
106-
# quadrature loop
107-
for i in 1:length(qf.w)
108-
# right-hand side : f times grad(P1),curl(bubble)
109-
eval_trafo!(QP.x, FEB.L2G, FEB.xref[i])
110-
QP.xref = FEB.xref[i]
111-
data(data_eval, QP)
112-
data_eval .*= xCellVolumes[cell] * qf.w[i]
113-
for dof in 1:nidofs
114-
for k in 1:ncomponents
115-
if dof < 3
116-
lb[dof] += data_eval[k] * basisvalsP1[k, dof, i]
117-
elseif dof == 3
118-
lb[dof] += data_eval[k] * basisvalsB[k, 1, i]
119-
end
120-
end
121-
122-
# mass matrix of interior basis functions
123-
for dof2 in 1:(nidofs - 1)
124-
temp = 0
125-
for k in 1:ncomponents
126-
temp += basisvals[k, interior_offset + dof, i] * basisvalsP1[k, dof2, i]
127-
end
128-
IMM[dof2, dof] += temp * xCellVolumes[cell] * qf.w[i]
129-
end
130-
temp = 0
131-
for k in 1:ncomponents
132-
temp += basisvals[k, interior_offset + dof, i] * basisvalsB[k, 1, i]
133-
end
134-
IMM[3, dof] += temp * xCellVolumes[cell] * qf.w[i]
135-
136-
# mass matrix of face basis functions
137-
for dof2 in 1:interior_offset
138-
temp = 0
139-
if dof < 3
140-
for k in 1:ncomponents
141-
temp += basisvalsP1[k, dof, i] * basisvals[k, dof2, i]
142-
end
143-
elseif dof == 3
144-
for k in 1:ncomponents
145-
temp += basisvalsB[k, 1, i] * basisvals[k, dof2, i]
146-
end
147-
end
148-
IMM_face[dof, dof2] += temp * xCellVolumes[cell] * qf.w[i]
149-
end
150-
end
151-
end
152-
153-
# subtract face interpolation from right-hand side
154-
for dof in 1:nidofs, dof2 in 1:interior_offset
155-
lb[dof] -= Target[xCellDofs[dof2, cell]] * IMM_face[dof, dof2]
156-
end
52+
interpolate!(Target, FE, ON_FACES, exact_function!; items = subitems, kwargs...)
15753

158-
# solve local system
159-
for dof in 1:nidofs
160-
interiordofs[dof] = xCellDofs[interior_offset + dof, cell]
161-
end
162-
Target[interiordofs] = IMM \ lb
163-
end
164-
return
54+
# set interior dofs such that moments with ∇P1 and curl(b) are preserved
55+
# (b is the cell bubble)
56+
get_interpolator(FE, ON_CELLS).evaluate!(Target, exact_function!, items; kwargs...)
16557
end
16658

16759
## only normalfluxes on faces

src/fedefs/hdiv_rt0.jl

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,19 @@ isdefined(FEType::Type{<:HDIVRT0}, ::Type{<:Quadrilateral2D}) = true
3535
isdefined(FEType::Type{<:HDIVRT0}, ::Type{<:Tetrahedron3D}) = true
3636
isdefined(FEType::Type{<:HDIVRT0}, ::Type{<:Hexahedron3D}) = true
3737

38-
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, data; items = [], kwargs...) where {T, Tv, Ti, FEType <: HDIVRT0, APT}
39-
xFaceNormals = FE.dofgrid[FaceNormals]
40-
if items == []
41-
items = 1:size(xFaceNormals, 2)
42-
end
38+
function RT0_normalflux_eval!(result, f, qpinfo)
39+
return result[1] = dot(f, qpinfo.normal)
40+
end
41+
init_interpolator!(FES::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}) where {Tv, Ti, FEType <: HDIVRT0, APT} = FaceFluxEvaluator(RT0_normalflux_eval!, FES, ON_FACES)
4342

44-
# compute exact face means
45-
data_eval = zeros(T, get_ncomponents(FEType))
46-
function normalflux_eval(result, qpinfo)
47-
data(data_eval, qpinfo)
48-
return result[1] = dot(data_eval, view(xFaceNormals, :, qpinfo.item))
49-
end
50-
return integrate!(Target, FE.dofgrid, ON_FACES, normalflux_eval; items = items, kwargs...)
43+
function ExtendableGrids.interpolate!(Target::AbstractArray{T, 1}, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_FACES}, exact_function!; items = [], kwargs...) where {T, Tv, Ti, FEType <: HDIVRT0, APT}
44+
return get_interpolator(FE, ON_FACES).evaluate!(Target, exact_function!, items; kwargs...)
5145
end
5246

53-
function ExtendableGrids.interpolate!(Target, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_CELLS}, data; items = [], kwargs...) where {Tv, Ti, FEType <: HDIVRT0, APT}
47+
function ExtendableGrids.interpolate!(Target, FE::FESpace{Tv, Ti, FEType, APT}, ::Type{ON_CELLS}, exact_function!; items = [], kwargs...) where {Tv, Ti, FEType <: HDIVRT0, APT}
5448
# delegate cell faces to face interpolation
5549
subitems = slice(FE.dofgrid[CellFaces], items)
56-
return interpolate!(Target, FE, ON_FACES, data; items = subitems, kwargs...)
50+
return interpolate!(Target, FE, ON_FACES, exact_function!; items = subitems, kwargs...)
5751
end
5852

5953
# only normalfluxes on faces

0 commit comments

Comments
 (0)