1- # # [Tutorial: Hybridizable Discontinuous Galerkin Method for the Poisson equation]
2- #
31# In this tutorial, we will implement a Hybridizable Discontinuous Galerkin (HDG) method
42# for solving the Poisson equation. The HDG method is an efficient variant of DG methods
5- # that introduces an auxiliary variable λ on mesh interfaces to reduce the global system size.
3+ # that introduces an auxiliary variable m on mesh interfaces to reduce the global system size.
64#
7- # ## The Poisson Problem
5+ # ## HDG Discretization
86#
97# We consider the Poisson equation with Dirichlet boundary conditions:
108#
1513# \end{aligned}
1614# ```
1715#
18- # ## HDG Discretization
19- #
2016# The HDG method first rewrites the problem as a first-order system:
2117#
2218# ```math
2319# \begin{aligned}
2420# \boldsymbol{q} + \nabla u &= \boldsymbol{0} \quad \text{in} \quad \Omega\\
25- # \nabla \cdot \boldsymbol{q} &= - f \quad \text{in} \quad \Omega\\
21+ # \nabla \cdot \boldsymbol{q} &= f \quad \text{in} \quad \Omega\\
2622# u &= g \quad \text{on} \quad \partial\Omega
2723# \end{aligned}
2824# ```
2925#
3026# The HDG discretization introduces three variables:
3127# - ``\boldsymbol{q}_h``: the approximation to the flux ``\boldsymbol{q}``
3228# - ``u_h``: the approximation to the solution ``u``
33- # - ``\lambda_h ``: the approximation to the trace of ``u`` on element faces
29+ # - ``m_h ``: the approximation to the trace of ``u`` on element faces
3430#
35- # The method is characterized by:
36- # 1. Local discontinuous approximation for ``(\boldsymbol{q}_h,u_h)`` in each element
37- # 2. Continuous approximation for ``\lambda_h`` on element faces
38- # 3. Numerical flux ``\widehat{\boldsymbol{q}}_h = \boldsymbol{q}_h + \tau(u_h - \lambda_h)\boldsymbol{n}``
31+ # Numerical fluxes are defindes as
3932#
40- # where τ is a stabilization parameter.
33+ # ```math
34+ # \widehat{\boldsymbol{q}}_h = \boldsymbol{q}_h + \tau(u_h - m_h)\boldsymbol{n}
35+ # ```
36+ #
37+ # where $\tau$ is a stabilization parameter.
4138#
4239# First, let's load the required Gridap packages:
4340
@@ -54,108 +51,105 @@ using Gridap.CellData
5451
5552u (x) = sin (2 * π* x[1 ])* sin (2 * π* x[2 ])
5653q (x) = - ∇ (u)(x) # Define the flux q = -∇u
57- f (x) = (∇ ⋅ q)(x) # Source term f = -Δu = -∇⋅(∇u)
54+ f (x) = (∇ ⋅ q)(x) # Source term f = -Δu = -∇⋅(∇u)$
5855
59- # ## Mesh Generation
56+ # ## Geometry
6057#
61- # Create a 3D simplicial mesh from a Cartesian grid:
58+ # We generate a D-dimensional simplicial mesh from a Cartesian grid:
6259
6360D = 2 # Problem dimension
6461nc = Tuple (fill (8 , D)) # 4 cells in each direction
6562domain = Tuple (repeat ([0 , 1 ], D)) # Unit cube domain
6663model = simplexify (CartesianDiscreteModel (domain,nc))
6764
68- # ## Volume and Interface Triangulations
65+ # From this mesh, we will require two triangulations where to define our HDG spaces:
6966#
70- # HDG methods require two types of meshes:
71- # 1. Volume mesh for element interiors
72- # 2. Skeleton mesh for element interfaces
67+ # 1. A cell triangulation $\Omega$, for the volume variables
68+ # 2. A face triangulation $\Gamma$, for the skeleton variables
7369#
74- # We also need patch-wise triangulations for local computations:
70+ # These are given by
7571
7672Ω = Triangulation (ReferenceFE{D}, model) # Volume triangulation
7773Γ = Triangulation (ReferenceFE{D- 1 }, model) # Skeleton triangulation
7874
75+ # ## PatchTopology and PatchTriangulation
76+ #
77+ # A key aspect of hybrid methods is the use of static condensation, which is the
78+ # elimination of cell unknowns to reduce the size of the global system.
79+ # To achieve this, we need to be able to assemble and solve local problems on each cell, that
80+ # involve
81+ # - contributions from the cell itself
82+ # - contributions from the cell faces
83+ # To this end, Gridap provides a general framework for patch-assembly and solves. The idea
84+ # is to define a patch decomposition of the mesh (in this case, a patch is a cell and its sourrounding
85+ # faces). We can then gather contributions for each patch, solve the local problems, and
86+ # assemble the results into the global system.
87+ #
88+ # The following code creates the required `PatchTopology` for the problem at hand. We then
89+ # take d-dimensional slices of it by the means of `PatchTriangulation` and `PatchBoundaryTriangulation`.
90+ # These are the `Triangulation`s we will integrate our weakform over.
91+
7992ptopo = Geometry. PatchTopology (model)
8093Ωp = Geometry. PatchTriangulation (model,ptopo) # Patch volume triangulation
8194Γp = Geometry. PatchBoundaryTriangulation (model,ptopo) # Patch skeleton triangulation
8295
83- # ## Reference Finite Elements
96+ # ## FESpaces
8497#
8598# HDG uses three different finite element spaces:
86- # 1. Vector-valued space for the flux q (Q)
87- # 2. Scalar space for the solution u (V)
88- # 3. Scalar space for the interface variable λ (M)
99+ # 1. A vector-valued space for the flux q (Q)
100+ # 2. A scalar space for the solution u (V)
101+ # 3. A scalar space for the interface variable m (M)
102+ #
103+ # We then define discontinuous finite element spaces of the approppriate order, locally $\mathbb{P}^k$.
104+ # Note that only the skeletal space has Dirichlet boundary conditions.
89105
90106order = 1 # Polynomial order
91107reffe_Q = ReferenceFE (lagrangian, VectorValue{D, Float64}, order; space= :P )
92108reffe_V = ReferenceFE (lagrangian, Float64, order; space= :P )
93109reffe_M = ReferenceFE (lagrangian, Float64, order; space= :P )
94110
95- # ## Test and Trial Spaces
96- #
97- # Create discontinuous cell spaces for volume variables (q,u) and
98- # a discontinous face space for the interface variable λ:
99-
100- # Test spaces
101111V = TestFESpace (Ω, reffe_V; conformity= :L2 ) # Discontinuous vector space
102112Q = TestFESpace (Ω, reffe_Q; conformity= :L2 ) # Discontinuous scalar space
103113M = TestFESpace (Γ, reffe_M; conformity= :L2 , dirichlet_tags= " boundary" ) # Interface space
104-
105- # Only the skeleton space has Dirichlet BC
106114N = TrialFESpace (M, u)
107115
108116# ## MultiField Structure
109117#
110- # Group the spaces for q, u, and λ using MultiField:
118+ # Since we are doing static condensation, we need assemble by blocks. In particular, the
119+ # `StaticCondensationOperator` expects the variables to be groupped in two blocks:
120+ # - The eliminated variables (in this case, the volume variables q and u)
121+ # - The retained variables (in this case, the interface variable m)
122+ # We will assemble by blocks using the `BlockMultiFieldStyle` API.
111123
112- mfs = MultiField . BlockMultiFieldStyle (2 ,(2 ,1 )) # Special blocking for efficient static condensation
113- X = MultiFieldFESpace ([V, Q, N];style= mfs)
124+ mfs = BlockMultiFieldStyle (2 ,(2 ,1 )) # Special blocking for efficient static condensation
125+ X = MultiFieldFESpace ([V, Q, N]; style= mfs)
114126
115- # ## Integration Setup
127+ # ## Weak Form and integration
116128#
117- # Define measures for volume and face integrals:
118129
119130degree = 2 * (order+ 1 ) # Integration degree
120- dΩp = Measure (Ωp,degree) # Volume measure
121- dΓp = Measure (Γp,degree) # Surface measure
122-
123- # ## HDG Parameters
124- #
125- # The stabilization parameter τ affects the stability and accuracy of the method:
131+ dΩp = Measure (Ωp,degree) # Volume measure, on the patch triangulation
132+ dΓp = Measure (Γp,degree) # Surface measure, on the patch boundary triangulation
126133
127134τ = 1.0 # HDG stabilization parameter
128135
129- # ## Weak Form
130- #
131- # The HDG weak form consists of three equations coupling q, u, and λ.
132- # We need operators to help define the weak form:
133-
134136n = get_normal_vector (Γp) # Face normal vector
135137Πn (u) = u⋅ n # Normal component
136138Π (u) = change_domain (u,Γp,DomainStyle (u)) # Project to skeleton
137139
138- # The bilinear and linear forms are:
139- # 1. Volume integrals for flux and primal equations
140- # 2. Interface integrals for hybridization
141- # 3. Stabilization terms with parameter τ
142-
143140a ((uh,qh,sh),(vh,wh,lh)) = ∫ ( qh⋅ wh - uh* (∇⋅ wh) - qh⋅ ∇ (vh) )dΩp + ∫ (sh* Πn (wh))dΓp +
144141 ∫ ((Πn (qh) + τ* (Π (uh) - sh))* (Π (vh) + lh))dΓp
145142l ((vh,wh,lh)) = ∫ ( f* vh )dΩp
146143
147144# ## Static Condensation and Solution
148145#
149- # A key feature of HDG is static condensation - eliminating volume variables
150- # to get a smaller system for λ only:
146+ # With all these ingredients, we can now build our statically-condensed operator ans
147+ # solve the problem. Note that we are solving a scatically-condensed system. We can
148+ # retrieve the internal `AffineFEOperator` from `op.sc_op`.
151149
152150op = MultiField. StaticCondensationOperator (ptopo,X,a,l)
153151uh, qh, sh = solve (op)
154152
155- # ## Error Analysis
156- #
157- # Compute the L2 error between numerical and exact solutions:
158-
159153dΩ = Measure (Ω,degree)
160154eh = uh - u
161155l2_uh = sqrt (sum (∫ (eh⋅ eh)* dΩ))
0 commit comments