Skip to content

Commit ef50b80

Browse files
authored
fixes and weight function for reconstruction operators (#47)
1 parent 3ddeb9e commit ef50b80

File tree

6 files changed

+175
-40
lines changed

6 files changed

+175
-40
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGES
22

3+
## v1.4.0 July 17, 2025
4+
- added new weighted reconstruction operator `WeightedReconstruct` (so far only for H1BR{2})
5+
- fixed H1CR{2} reconstruction
6+
37
## v1.3.0 July 09, 2025
48
- some bugfixes related to new template parameter from 1.2.0
59
- @show of FEVectorBlock does not crash anymore

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ExtendableFEMBase"
22
uuid = "12fb9182-3d4c-4424-8fd1-727a0899810c"
33
authors = ["Christian Merdon <[email protected]>", "Patrick Jaap <[email protected]>"]
4-
version = "1.3.0"
4+
version = "1.4.0"
55

66
[deps]
77
DiffResults = "163ba53b-c6d8-5494-b064-1a9d43ac40c5"

src/ExtendableFEMBase.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,12 @@ export displace_mesh, displace_mesh!
127127

128128
include("reconstructionhandlers.jl")
129129
export ReconstructionHandler, get_rcoefficients!
130+
export Reconstruct, WeightedReconstruct
130131

131132
include("feevaluator.jl")
132133
export FEEvaluator, update_basis!, eval_febe!
133134

134135
include("reconstructionoperators.jl")
135-
export Reconstruct
136136

137137
include("accumvector.jl")
138138
export AccumulatingVector

src/reconstructionhandlers.jl

Lines changed: 98 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
abstract type ReconstructionOperator{FETypeR, O} <: AbstractFunctionOperator end
2+
3+
"""
4+
$(TYPEDEF)
5+
6+
reconstruction operator: evaluates a reconstructed version of the finite element function.
7+
8+
FETypeR specifies the reconstruction space (needs to be defined for the finite element that it is applied to).
9+
O specifies the StandardFunctionOperator that shall be evaluated.
10+
"""
11+
abstract type Reconstruct{FETypeR, O} <: ReconstructionOperator{FETypeR, O} end
12+
13+
14+
"""
15+
WeightedReconstruct{FETypeR, O, w} <: Reconstruct{FETypeR, O}
16+
17+
Weighted reconstruction operator:
18+
evaluates a reconstructed version of a finite element function, multiplied by a weight function.
19+
**Warning**: This is a prototype and currently only works for the HDIVRT0{2} and HDIVBDM1{2} reconstruction of H1BR{2}.
20+
21+
# Parameters
22+
- `FETypeR`: The reconstruction finite element space type (target space for reconstruction).
23+
- `O`: The standard function operator to be evaluated (e.g., identity, gradient, etc.).
24+
- `w`: The type of the weight function (should be callable, e.g., a function or functor of type w(x)).
25+
"""
26+
abstract type WeightedReconstruct{FETypeR, O, w} <: Reconstruct{FETypeR, O} end
27+
28+
weight_type(::Type{<:WeightedReconstruct{FETypeR, O, w}}) where {FETypeR, O, w} = w
29+
30+
131
################## SPECIAL INTERPOLATORS ####################
232

333
"""
@@ -69,18 +99,33 @@ abstract type ReconstructionDofs{FE1, FE2, AT} <: AbstractGridIntegerArray2D end
6999
"""
70100
$(TYPEDEF)
71101
102+
abstract grid component type that can be used to funnel reconstruction weights into the operator
103+
(default is 1)
104+
"""
105+
abstract type ReconstructionWeights{AT} <: AbstractGridFloatArray2D end
106+
107+
"""
108+
$(TYPEDEF)
109+
72110
struct for storing information needed to evaluate a reconstruction operator
73111
"""
74-
struct ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}
112+
struct ReconstructionHandler{Tv, Ti, RT, FE1, FE2, AT, EG, F}
75113
FES::FESpace{Tv, Ti, FE1, ON_CELLS}
76114
FER::FESpace{Tv, Ti, FE2, ON_CELLS}
115+
xCoordinates::Array{Tv, 2}
116+
xFaceNodes::Adjacency{Ti}
77117
xFaceVolumes::Array{Tv, 1}
78118
xFaceNormals::Array{Tv, 2}
79119
xCellFaceOrientations::Adjacency{Ti}
80120
xCellFaces::Adjacency{Ti}
81121
interior_offset::Int
82122
interior_ndofs::Int
83123
interior_coefficients::Matrix{Tv} # coefficients for interior basis functions are precomputed
124+
weight::F
125+
end
126+
127+
function default_weight_function(x)
128+
return 1
84129
end
85130

86131
"""
@@ -90,7 +135,7 @@ generates a reconstruction handler
90135
returns the local coefficients need to evaluate a reconstruction operator
91136
of one finite element space into another
92137
"""
93-
function ReconstructionHandler(FES::FESpace{Tv, Ti, FE1, APT}, FES_Reconst::FESpace{Tv, Ti, FE2, APT}, AT, EG) where {Tv, Ti, FE1, FE2, APT}
138+
function ReconstructionHandler(FES::FESpace{Tv, Ti, FE1, APT}, FES_Reconst::FESpace{Tv, Ti, FE2, APT}, AT, EG, RT, weight = default_weight_function) where {Tv, Ti, FE1, FE2, APT}
94139
xgrid = FES.xgrid
95140
interior_offset = interior_dofs_offset(AT, FE2, EG)
96141
interior_ndofs = get_ndofs(AT, FE2, EG) - interior_offset
@@ -100,11 +145,14 @@ function ReconstructionHandler(FES::FESpace{Tv, Ti, FE1, APT}, FES_Reconst::FESp
100145
interior_ndofs = 0
101146
coeffs = zeros(Tv, 0, 0)
102147
end
148+
103149
xFaceVolumes = xgrid[FaceVolumes]
104150
xFaceNormals = xgrid[FaceNormals]
151+
xCoordinates = xgrid[Coordinates]
152+
xFaceNodes = xgrid[FaceNodes]
105153
xCellFaceOrientations = dim_element(EG) == 2 ? xgrid[CellFaceSigns] : xgrid[CellFaceOrientations]
106154
xCellFaces = xgrid[CellFaces]
107-
return ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}(FES, FES_Reconst, xFaceVolumes, xFaceNormals, xCellFaceOrientations, xCellFaces, interior_offset, interior_ndofs, coeffs)
155+
return ReconstructionHandler{Tv, Ti, RT, FE1, FE2, AT, EG, typeof(weight)}(FES, FES_Reconst, xCoordinates, xFaceNodes, xFaceVolumes, xFaceNormals, xCellFaceOrientations, xCellFaces, interior_offset, interior_ndofs, coeffs, weight)
108156
end
109157

110158
"""
@@ -113,7 +161,7 @@ $(TYPEDSIGNATURES)
113161
caller function to extract the coefficients of the reconstruction
114162
on an item
115163
"""
116-
function get_rcoefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}, item) where {Tv, Ti, FE1, FE2, AT, EG}
164+
function get_rcoefficients!(coefficients, RH::ReconstructionHandler, item)
117165
boundary_coefficients!(coefficients, RH, item)
118166
for dof in 1:size(coefficients, 1), k in 1:RH.interior_ndofs
119167
coefficients[dof, RH.interior_offset + k] = RH.interior_coefficients[(dof - 1) * RH.interior_ndofs + k, item]
@@ -428,7 +476,7 @@ boundary_coefficients!(coefficients, RH::ReconstructionHandler, cell)
428476
429477
generates the coefficients for the facial dofs of the reconstruction operator on the cell
430478
"""
431-
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, <:H1CR{ncomponents}, <:HDIVRT0{ncomponents}, <:ON_CELLS, EG}, cell) where {Tv, Ti, ncomponents, EG}
479+
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, <:Reconstruct, <:H1CR{ncomponents}, <:HDIVRT0{ncomponents}, <:ON_CELLS, EG}, cell) where {Tv, Ti, ncomponents, EG}
432480
xFaceVolumes = RH.xFaceVolumes
433481
xFaceNormals = RH.xFaceNormals
434482
xCellFaces = RH.xCellFaces
@@ -446,59 +494,93 @@ end
446494

447495
const _P1_INTO_BDM1_COEFFS = [-1 // 12, 1 // 12]
448496

449-
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}, cell) where {Tv, Ti, FE1 <: H1BR{2}, FE2 <: HDIVBDM1{2}, AT <: ON_CELLS, EG <: Union{Triangle2D, Quadrilateral2D}}
497+
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, RT, FE1, FE2, AT, EG}, cell) where {Tv, Ti, RT <: Reconstruct, FE1 <: H1BR{2}, FE2 <: HDIVBDM1{2}, AT <: ON_CELLS, EG <: Union{Triangle2D, Quadrilateral2D}}
450498
xFaceVolumes = RH.xFaceVolumes
451499
xFaceNormals = RH.xFaceNormals
452500
xCellFaceSigns = RH.xCellFaceOrientations
453501
xCellFaces = RH.xCellFaces
502+
xFaceNodes = RH.xFaceNodes
503+
xCoordinates = RH.xCoordinates
454504
face_rule = local_cellfacenodes(EG)
455505
nnodes = size(face_rule, 1)
456506
nfaces = size(face_rule, 2)
457507
node = 0
458508
face = 0
459509
BDM1_coeffs = _P1_INTO_BDM1_COEFFS
510+
weight = RH.weight
511+
xmid = zeros(Tv, 2)
512+
w = ones(Tv, 2)
460513
for f in 1:nfaces
461514
face = xCellFaces[f, cell]
515+
x1 = view(xCoordinates, :, xFaceNodes[1, face])
516+
x2 = view(xCoordinates, :, xFaceNodes[2, face])
517+
xmid .= 0.5 * (x1 .+ x2)
518+
if xCellFaceSigns[f, cell] == -1
519+
w[1] = weight(x2)
520+
w[2] = weight(x1)
521+
else
522+
w[1] = weight(x1)
523+
w[2] = weight(x2)
524+
end
525+
wmid = weight(xmid)
462526
for n in 1:nnodes
463527
node = face_rule[n, f]
464528
for k in 1:2
465529
# RT0 reconstruction coefficients for P1 functions on reference element
466-
coefficients[nfaces * (k - 1) + node, 2 * (f - 1) + 1] = 1 // 2 * xFaceVolumes[face] * xFaceNormals[k, face]
530+
coefficients[nfaces * (k - 1) + node, 2 * (f - 1) + 1] = xFaceVolumes[face] * (1 // 6 * w[n] + 1 // 3 * wmid) * xFaceNormals[k, face]
467531
# BDM1 reconstruction coefficients for P1 functions on reference element
468-
coefficients[nfaces * (k - 1) + node, 2 * (f - 1) + 2] = BDM1_coeffs[n] * xFaceVolumes[face] * xFaceNormals[k, face] * xCellFaceSigns[f, cell]
532+
coefficients[nfaces * (k - 1) + node, 2 * (f - 1) + 2] = xFaceVolumes[face] * xFaceNormals[k, face] * xCellFaceSigns[f, cell] * (BDM1_coeffs[n] * w[n])
469533
end
470534
end
471535
# RT0 reconstruction coefficients for face bubbles on reference element
472-
coefficients[nfaces * 2 + f, 2 * (f - 1) + 1] = xFaceVolumes[face]
536+
coefficients[nfaces * 2 + f, 2 * (f - 1) + 1] = xFaceVolumes[face] * wmid
473537
end
538+
474539
return nothing
475540
end
476541

477-
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}, cell) where {Tv, Ti, FE1 <: H1BR{2}, FE2 <: HDIVRT0{2}, AT <: ON_CELLS, EG <: Union{Triangle2D, Quadrilateral2D}}
542+
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, RT, FE1, FE2, AT, EG}, cell) where {Tv, Ti, RT <: Reconstruct, FE1 <: H1BR{2}, FE2 <: HDIVRT0{2}, AT <: ON_CELLS, EG <: Union{Triangle2D, Quadrilateral2D}}
478543
xFaceVolumes = RH.xFaceVolumes
479544
xFaceNormals = RH.xFaceNormals
480545
xCellFaces = RH.xCellFaces
546+
xCellFaceSigns = RH.xCellFaceOrientations
547+
xFaceNodes = RH.xFaceNodes
548+
xCoordinates = RH.xCoordinates
481549
face_rule = local_cellfacenodes(EG)
482550
nnodes = size(face_rule, 1)
483551
nfaces = size(face_rule, 2)
484552
node = 0
485553
face = 0
554+
weight = RH.weight
555+
xmid = zeros(Tv, 2)
556+
w = ones(Tv, 2)
486557
for f in 1:nfaces
487558
face = xCellFaces[f, cell]
559+
x1 = view(xCoordinates, :, xFaceNodes[1, face])
560+
x2 = view(xCoordinates, :, xFaceNodes[2, face])
561+
xmid .= 0.5 * (x1 .+ x2)
562+
if xCellFaceSigns[f, cell] == -1
563+
w[1] = weight(x2)
564+
w[2] = weight(x1)
565+
else
566+
w[1] = weight(x1)
567+
w[2] = weight(x2)
568+
end
569+
wmid = weight(xmid)
488570
# reconstruction coefficients for P1 functions on reference element
489571
for n in 1:nnodes
490572
node = face_rule[n, f]
491573
for k in 1:2
492-
coefficients[nfaces * (k - 1) + node, f] = 1 // 2 * xFaceVolumes[face] * xFaceNormals[k, face]
574+
coefficients[nfaces * (k - 1) + node, f] = xFaceVolumes[face] * (1 // 6 * w[n] + 1 // 3 * wmid) * xFaceNormals[k, face]
493575
end
494576
end
495577
# reconstruction coefficients for face bubbles on reference element
496-
coefficients[2 * nfaces + f, f] = xFaceVolumes[face]
578+
coefficients[2 * nfaces + f, f] = xFaceVolumes[face] * wmid
497579
end
498580
return nothing
499581
end
500582

501-
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}, cell) where {Tv, Ti, FE1 <: H1P2B{2, 2}, FE2 <: HDIVRT1{2}, AT <: ON_CELLS, EG <: Triangle2D}
583+
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, RT, FE1, FE2, AT, EG}, cell) where {Tv, Ti, RT <: Reconstruct, FE1 <: H1P2B{2, 2}, FE2 <: HDIVRT1{2}, AT <: ON_CELLS, EG <: Triangle2D}
502584
xFaceVolumes = RH.xFaceVolumes
503585
xFaceNormals = RH.xFaceNormals
504586
xCellFaceSigns = RH.xCellFaceOrientations
@@ -529,7 +611,7 @@ function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti,
529611
return nothing
530612
end
531613

532-
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}, cell) where {Tv, Ti, FE1 <: H1P2B{2, 2}, FE2 <: HDIVBDM2{2}, AT <: ON_CELLS, EG <: Triangle2D}
614+
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, RT, FE1, FE2, AT, EG}, cell) where {Tv, Ti, RT <: Reconstruct, FE1 <: H1P2B{2, 2}, FE2 <: HDIVBDM2{2}, AT <: ON_CELLS, EG <: Triangle2D}
533615
xFaceVolumes = RH.xFaceVolumes
534616
xFaceNormals = RH.xFaceNormals
535617
xCellFaceSigns = RH.xCellFaceOrientations
@@ -567,7 +649,7 @@ function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti,
567649
end
568650

569651

570-
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}, cell) where {Tv, Ti, FE1 <: H1BR{3}, FE2 <: HDIVRT0{3}, AT <: ON_CELLS, EG <: Tetrahedron3D}
652+
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, RT, FE1, FE2, AT, EG}, cell) where {Tv, Ti, RT <: Reconstruct, FE1 <: H1BR{3}, FE2 <: HDIVRT0{3}, AT <: ON_CELLS, EG <: Tetrahedron3D}
571653
xFaceVolumes = RH.xFaceVolumes
572654
xFaceNormals = RH.xFaceNormals
573655
xCellFaces = RH.xCellFaces
@@ -592,7 +674,7 @@ end
592674

593675
const _P1_INTO_BDM1_COEFFS_3D = [-1 // 36 -1 // 36 1 // 18; -1 // 36 1 // 18 -1 // 36; 1 // 18 -1 // 36 -1 // 36]
594676

595-
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, FE1, FE2, AT, EG}, cell) where {Tv, Ti, FE1 <: H1BR{3}, FE2 <: HDIVBDM1{3}, AT <: ON_CELLS, EG <: Tetrahedron3D}
677+
function boundary_coefficients!(coefficients, RH::ReconstructionHandler{Tv, Ti, RT, FE1, FE2, AT, EG}, cell) where {Tv, Ti, RT <: Reconstruct, FE1 <: H1BR{3}, FE2 <: HDIVBDM1{3}, AT <: ON_CELLS, EG <: Tetrahedron3D}
596678
xFaceVolumes = RH.xFaceVolumes
597679
xFaceNormals = RH.xFaceNormals
598680
xCellFaces = RH.xCellFaces

src/reconstructionoperators.jl

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,24 @@
1-
abstract type ReconstructionOperator <: AbstractFunctionOperator end
1+
StandardFunctionOperator(::Type{<:ReconstructionOperator{FETypeR, O}}) where {FETypeR, O} = O
2+
ReconstructionSpace(::Type{<:ReconstructionOperator{FETypeR, O}}) where {FETypeR, O} = FETypeR
23

3-
"""
4-
$(TYPEDEF)
5-
6-
reconstruction operator: evaluates a reconstructed version of the finite element function.
7-
8-
FETypeR specifies the reconstruction space (needs to be defined for the finite element that it is applied to).
9-
O specifies the StandardFunctionOperator that shall be evaluated.
10-
"""
11-
abstract type Reconstruct{FETypeR, O} <: ReconstructionOperator where {FETypeR <: AbstractFiniteElement, O <: StandardFunctionOperator} end # calculates the jump between both sides of the face
12-
13-
14-
StandardFunctionOperator(::Type{Reconstruct{FETypeR, O}}) where {FETypeR, O} = O
15-
ReconstructionSpace(::Type{Reconstruct{FETypeR, O}}) where {FETypeR, O} = FETypeR
16-
17-
NeededDerivative4Operator(::Type{Reconstruct{FETypeR, O}}) where {FETypeR, O} = NeededDerivative4Operator(O)
18-
Length4Operator(::Type{Reconstruct{FETypeR, O}}, xdim, nc) where {FETypeR, O} = Length4Operator(O, xdim, nc)
4+
NeededDerivative4Operator(::Type{<:ReconstructionOperator{FETypeR, O}}) where {FETypeR, O} = NeededDerivative4Operator(O)
5+
Length4Operator(::Type{<:ReconstructionOperator{FETypeR, O}}, xdim, nc) where {FETypeR, O} = Length4Operator(O, xdim, nc)
196
DefaultName4Operator(::Type{Reconstruct{FETypeR, O}}) where {FETypeR, O} = "R(" * DefaultName4Operator(O) * ")"
7+
DefaultName4Operator(::Type{WeightedReconstruct{FETypeR, O, w}}) where {FETypeR, O, w} = "wR(r" * DefaultName4Operator(O) * ")"
208

21-
struct FEReconstEvaluator{T, TvG, TiG, FEType, FEType2, stdop, O <: ReconstructionOperator} <: FEEvaluator{T, TvG, TiG}
9+
struct FEReconstEvaluator{T, TvG, TiG, FEType, FEType2, stdop, RH} <: FEEvaluator{T, TvG, TiG}
2210
citem::Base.RefValue{Int} # current item
2311
FE::FESpace{TvG, TiG, FEType} # link to full FE (e.g. for coefficients)
2412
FEB::SingleFEEvaluator{T, TvG, TiG, stdop, FEType2} # FEBasisEvaluator for stdop in reconstruction space
2513
cvals::Array{T, 3} # current operator vals on item (reconstruction)
2614
coefficients::Array{TvG, 2} # additional coefficients for reconstruction
27-
reconst_handler::ReconstructionHandler{T, TiG} # handler for reconstruction coefficients
15+
reconst_handler::RH # handler for reconstruction coefficients
2816
end
2917

3018
# constructor for reconstruction operators
3119
function FEEvaluator(
3220
FE::FESpace{TvG, TiG, FEType, FEAPT},
33-
operator::Type{<:Reconstruct{FETypeReconst, stdop}},
21+
operator::Type{<:ReconstructionOperator{FETypeReconst, stdop}},
3422
qrule::QuadratureRule{TvR, EG},
3523
xgrid = FE.xgrid;
3624
L2G = nothing,
@@ -65,9 +53,21 @@ function FEEvaluator(
6553
FEB = FEEvaluator(FE2, stdop, qrule, xgrid; L2G = L2G, T = T, AT = AT)
6654

6755
## reconstruction coefficient handler
68-
reconst_handler = ReconstructionHandler(FE, FE2, AT, EG)
56+
if operator <: WeightedReconstruct && FEType in [H1BR{2}]
57+
tf = weight_type(operator)
58+
reconst_handler = ReconstructionHandler(FE, FE2, AT, EG, operator, tf.instance)
59+
else
60+
if operator <: WeightedReconstruct
61+
@warn "weighted reconstruction not available for $FEType, ignoring the weight function"
62+
end
63+
reconst_handler = ReconstructionHandler(FE, FE2, AT, EG, operator)
64+
end
65+
66+
return FEReconstEvaluator{T, TvG, TiG, FEType, FETypeReconst, stdop, typeof(reconst_handler)}(FEB.citem, FE, FEB, cvals, coefficients2, reconst_handler)
67+
end
6968

70-
return FEReconstEvaluator{T, TvG, TiG, FEType, FETypeReconst, stdop, operator}(FEB.citem, FE, FEB, cvals, coefficients2, reconst_handler)
69+
function relocate_xref!(FEB::FEReconstEvaluator, new_xref)
70+
return relocate_xref!(FEB.FEB, new_xref)
7171
end
7272

7373
function update_basis!(FEBE::FEReconstEvaluator)

0 commit comments

Comments
 (0)