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)
8288mfs = MultiField. BlockMultiFieldStyle (2 ,(1 ,1 ))
8389X = MultiFieldFESpace ([V, N];style= mfs)
8490Y = 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
125143function projection_operator (V, Ω, dΩ)
126144 Π (u,Ω) = change_domain (u,Ω,DomainStyle (u))
@@ -132,6 +150,18 @@ function projection_operator(V, Ω, dΩ)
132150 return P
133151end
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+
135165function 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 )
153183PΓ = projection_operator (M, Γp, dΓp)
154184R = 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`
178208
179209l ((vΩ,vΓ)) = ∫ (f⋅ vΩ)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
183233global_assem = SparseMatrixAssembler (X,Y)
184234
@@ -199,7 +249,7 @@ eu = ui - u
199249l2u = sqrt (sum ( ∫ (eu * eu)dΩp))
200250h1u = l2u + sqrt (sum ( ∫ (∇ (eu) ⋅ ∇ (eu))dΩp))
201251
202- # ## Assembly with static condensation
252+ # ### Assembly with static condensation
203253
204254patch_assem = FESpaces. PatchAssembler (ptopo,X,Y)
205255
0 commit comments