Skip to content

Commit 2edeb22

Browse files
committed
Minor
1 parent 642c969 commit 2edeb22

File tree

1 file changed

+60
-10
lines changed

1 file changed

+60
-10
lines changed

src/poisson_hho.jl

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
# for solving the Poisson equation. HHO methods are a class of modern hybridizable finite element methods
44
# that provide optimal convergence rates while enabling static condensation for efficient solution.
55
#
6+
# HHO is a mathematically complex method. This tutorial will **NOT** cover the method nor
7+
# its mathematical foundations. You should be familiar with both before going into
8+
# the tutorial itself.
9+
# We also recommend going through the HDG tutorial first, which shares many of the
10+
# same concepts but is simpler to understand.
11+
#
612
# ## Problem statement
713
#
814
# We consider the Poisson equation with Dirichlet boundary conditions:
@@ -82,7 +88,6 @@ N = TrialFESpace(M,u)
8288
mfs = MultiField.BlockMultiFieldStyle(2,(1,1))
8389
X = MultiFieldFESpace([V, N];style=mfs)
8490
Y = MultiFieldFESpace([V, M];style=mfs)
85-
Xp = FESpaces.PatchFESpace(X,ptopo)
8691

8792
# ## PatchTopology and PatchTriangulation
8893
#
@@ -114,13 +119,26 @@ dΓp = Measure(Γp,qdegree)
114119
# A key feature of HHO is the use of local solves to define local projections of our bulk and
115120
# skeleton variables. Just like for static condensation, we will use patch assembly to
116121
# gather the contributions from each patch and solve the local problems.
122+
# The result is then an element of the space we are projecting to, given as a
123+
# linear combination of the basis of that space. This whole abstraction is taken
124+
# care of by the `LocalOperator` object.
125+
#
126+
# For the mixed-order Poisson problem, we require two local projections.
127+
#
128+
# ### L2 projection operator
117129
#
118-
# For the mixed-order Poisson problem, we require two local projections:
119-
# - First, an L2 local projection operator onto the mesh faces.
120-
# - Second, the so-called reconstruction operator. This operator is highly tied to the
121-
# ellipic projector, and projects our bulk-skeleton variable pair onto a bulk
122-
# space of higher order.
123-
# The operators are defined as follows:
130+
# First, an L2 local projection operator onto the mesh faces. This is the simplest
131+
# operator we can define, such that given $u$ in some undefined space, we find $Pu \in V$ st
132+
#
133+
# $$(Pu,q) = (u,q) \forall q \in V$$
134+
#
135+
# This signature for the `LocalOperator` assumes that the rhs and lhs for each local problem
136+
# are given by a single cell contribution (no patch assembly required).
137+
# Note also the use of `FESpaceWithoutBCs`, which strips the boundary conditions from the
138+
# space `V`. This is because we do not want to take into account boundary conditions
139+
# when projecting onto the space.
140+
# The local solve map is given by `LocalSolveMap`, which by default uses Julia's LU
141+
# factorization to solve the local problem exactly.
124142

125143
function projection_operator(V, Ω, dΩ)
126144
Π(u,Ω) = change_domain(u,Ω,DomainStyle(u))
@@ -132,6 +150,18 @@ function projection_operator(V, Ω, dΩ)
132150
return P
133151
end
134152

153+
# ### Reconstruction operator
154+
#
155+
# Finally, we build the so-called reconstruction operator. This operator is highly tied to the
156+
# ellipic projector, and projects our bulk-skeleton variable pair onto a bulk space of higher order.
157+
#
158+
# It's definition can be found in HHO literature, and requires solving a constrained
159+
# local problem on each cell and its faces. We therefore use patch assembly, and impose
160+
# our constraint using an additional space `Λ` as a local Lagrange multiplier.
161+
# Naturally, we want to eliminate the multiplier and return a solution in the reconstructed
162+
# space `L`. This is taken care of by the `LocalPenaltySolveMap`, and the kwarg `space_out = L`
163+
# which overrides the default behavior of returning a solution in the test space `Y`.
164+
135165
function reconstruction_operator(ptopo,order,X,Ω,Γp,dΩp,dΓp)
136166
L = FESpaces.PolytopalFESpace(Ω, Float64, order+1; space=:P)
137167
Λ = FESpaces.PolytopalFESpace(Ω, Float64, 0; space=:P)
@@ -153,7 +183,7 @@ end
153183
= projection_operator(M, Γp, dΓp)
154184
R = reconstruction_operator(ptopo,order,Y,Ωp,Γp,dΩp,dΓp)
155185

156-
# ## Weakform
186+
# ## Weakform and assembly
157187
#
158188
# We can now define:
159189
# - The consistency term `a`
@@ -178,7 +208,27 @@ end
178208

179209
l((vΩ,vΓ)) = (fvΩ)dΩp
180210

181-
# ## Assembly without static condensation
211+
# ### Patch-FESpaces
212+
#
213+
# An additional difficulty in HHO methods is that our reconstructed functions `R(u)` are
214+
# hard to assemble. They are defined on the cells, but depend on skeleton degrees of freedom.
215+
# We therefore cannot assemble them using the original FESpace `N`. Instead, we will create \
216+
# view of the original space that is defined on the patches, and can be used to assemble
217+
# the local contributions depending on `R`. It can be done by the means of `PatchFESpace`:
218+
219+
Xp = FESpaces.PatchFESpace(X,ptopo)
220+
221+
# ### Assembly without static condensation
222+
#
223+
# We can now proceed to evaluate and assemble all our contributions. Note that some of
224+
# the contributions depend on the reconstructed variables, e.g `a(u,v)`, and need to
225+
# be assembled using the `PatchFESpace` `Xp`, while others can be assembled using the original
226+
# FESpace `X` (e.g. `s(u,v)` and `l(v)`).
227+
# Assembly is therefore somewhat more complex than in the standard case. We need to
228+
# collect the contributions for every (test,trial) pair, and then merge them into a single
229+
# data structure that can be passed to the assembler.
230+
# In the case of mixed-order HHO, we only have two combinations, (`Xp`, `Xp`) and (`X`, `X`),
231+
# but the cross-terms appear also in the case of the original HHO formulation.
182232

183233
global_assem = SparseMatrixAssembler(X,Y)
184234

@@ -199,7 +249,7 @@ eu = ui - u
199249
l2u = sqrt(sum( (eu * eu)dΩp))
200250
h1u = l2u + sqrt(sum( ((eu) (eu))dΩp))
201251

202-
# ## Assembly with static condensation
252+
# ### Assembly with static condensation
203253

204254
patch_assem = FESpaces.PatchAssembler(ptopo,X,Y)
205255

0 commit comments

Comments
 (0)