1<a name="Intro"></a> 2<h1>Introduction</h1> 3 4@dealiiVideoLecture{15,16,17,17.25,17.5,17.75} 5 6This program is finally about one of the main features of deal.II: 7the use of adaptively (locally) refined meshes. The program is still 8based on step-4 and step-5, and, as you will see, it does not actually 9take very much code to enable adaptivity. Indeed, while we do a great 10deal of explaining, adaptive meshes can be added to an existing program 11with barely a dozen lines of additional code. The program shows what 12these lines are, as well as another important ingredient of adaptive 13mesh refinement (AMR): a criterion that can be used to determine whether 14it is necessary to refine a cell because the error is large on it, 15whether the cell can be coarsened because the error is particularly 16small on it, or whether we should just leave the cell as it is. We 17will discuss all of these issues in the following. 18 19 20<h3> What adaptively refined meshes look like </h3> 21 22There are a number of ways how one can adaptively refine meshes. The 23basic structure of the overall algorithm is always the same and consists 24of a loop over the following steps: 25- Solve the PDE on the current mesh; 26- Estimate the error on each cell using some criterion that is indicative 27 of the error; 28- Mark those cells that have large errors for refinement, mark those that have 29 particularly small errors for coarsening, and leave the rest alone; 30- Refine and coarsen the cells so marked to obtain a new mesh; 31- Repeat the steps above on the new mesh until the overall error is 32 sufficiently small. 33 34For reasons that are probably lost to history (maybe that these functions 35used to be implemented in FORTRAN, a language that does not care about 36whether something is spelled in lower or UPPER case letters, with programmers 37often choosing upper case letters habitually), the loop above is often 38referenced in publications about mesh adaptivity as the 39SOLVE-ESTIMATE-MARK-REFINE loop (with this spelling). 40 41Beyond this structure, however, there are a variety of ways to achieve 42this. Fundamentally, they differ in how exactly one generates one mesh 43from the previous one. 44 45If one were to use triangles (which deal.II does not do), then there are 46two essential possibilities: 47- Longest-edge refinement: In this strategy, a triangle marked for refinement 48 is cut into two by introducing one new edge from the midpoint of the longest 49 edge to the opposite vertex. Of course, the midpoint from the longest edge 50 has to somehow be balanced by *also* refining the cell on the other side of 51 that edge (if there is one). If the edge in question is also the longest 52 edge of the neighboring cell, then we can just run a new edge through the 53 neighbor to the opposite vertex; otherwise a slightly more involved 54 construction is necessary that adds more new vertices on at least one 55 other edge of the neighboring cell, and then may propagate to the neighbors 56 of the neighbor until the algorithm terminates. This is hard to describe 57 in words, and because deal.II does not use triangles not worth the time here. 58 But if you're curious, you can always watch video lecture 15 at the link 59 shown at the top of this introduction. 60- Red-green refinement: An alternative is what is called "red-green refinement". 61 This strategy is even more difficult to describe (but also discussed in the 62 video lecture) and has the advantage that the refinement does not propagate 63 beyond the immediate neighbors of the cell that we want to refine. It is, 64 however, substantially more difficult to implement. 65 66There are other variations of these approaches, but the important point is 67that they always generate a mesh where the lines where two cells touch 68are entire edges of both adjacent cells. With a bit of work, this strategy 69is readily adapted to three-dimensional meshes made from tetrahedra. 70 71Neither of these methods works for quadrilaterals in 2d and hexahedra in 3d, 72or at least not easily. The reason is that the transition elements created 73out of the quadrilateral neighbors of a quadrilateral cell that is to be refined 74would be triangles, and we don't want this. Consequently, 75the approach to adaptivity chosen in deal.II is to use grids in which 76neighboring cells may differ in refinement level by one. This then 77results in nodes on the interfaces of cells which belong to one 78side, but are unbalanced on the other. The common term for these is 79“hanging nodes”, and these meshes then look like this in a very 80simple situation: 81 82@image html hanging_nodes.png "A simple mesh with hanging nodes" 83 84A more complicated two-dimensional mesh would look like this (and is 85discussed in the "Results" section below): 86 87<img src="https://www.dealii.org/images/steps/developer/step_6_grid_5_ladutenko.svg" 88 alt="Fifth adaptively refined Ladutenko grid: the cells are clustered 89 along the inner circle." 90 width="300" height="300"> 91 92Finally, a three-dimensional mesh (from step-43) with such hanging nodes is shown here: 93 94<img src="https://www.dealii.org/images/steps/developer/step-43.3d.mesh.png" alt="" 95 width="300" height="300"> 96 97The first and third mesh are of course based on a square and a cube, but as the 98second mesh shows, this is not necessary. The important point is simply that we 99can refine a mesh independently of its neighbors (subject to the constraint 100that a cell can be only refined once more than its neighbors), but that we end 101up with these “hanging nodes” if we do this. 102 103 104<h3> Why adapatively refined meshes? </h3> 105 106Now that you have seen what these adaptively refined meshes look like, 107you should ask <i>why</i> we would want to do this. After all, we know from 108theory that if we refine the mesh globally, the error will go down to zero 109as 110@f{align*}{ 111 \|\nabla(u-u_h)\|_{\Omega} \le C h_\text{max}^p \| \nabla^{p+1} u \|_{\Omega}, 112@f} 113where $C$ is some constant independent of $h$ and $u$, 114$p$ is the polynomial degree of the finite element in use, and 115$h_\text{max}$ is the diameter of the largest cell. So if the 116<i>largest</i> cell is important, then why would we want to make 117the mesh fine in some parts of the domain but not all? 118 119The answer lies in the observation that the formula above is not 120optimal. In fact, some more work shows that the following 121is a better estimate (which you should compare to the square of 122the estimate above): 123@f{align*}{ 124 \|\nabla(u-u_h)\|_{\Omega}^2 \le C \sum_K h_K^{2p} \| \nabla^{p+1} u \|^2_K. 125@f} 126(Because $h_K\le h_\text{max}$, this formula immediately implies the 127previous one if you just pull the mesh size out of the sum.) 128What this formula suggests is that it is not necessary to make 129the <i>largest</i> cell small, but that the cells really only 130need to be small <i>where $\| \nabla^{p+1} u \|_K$ is large</i>! 131In other words: The mesh really only has to be fine where the 132solution has large variations, as indicated by the $p+1$st derivative. 133This makes intuitive sense: if, for example, we use a linear element 134$p=1$, then places where the solution is nearly linear (as indicated 135by $\nabla^2 u$ being small) will be well resolved even if the mesh 136is coarse. Only those places where the second derivative is large 137will be poorly resolved by large elements, and consequently 138that's where we should make the mesh small. 139 140Of course, this <i>a priori estimate</i> is not very useful 141in practice since we don't know the exact solution $u$ of the 142problem, and consequently, we cannot compute $\nabla^{p+1}u$. 143But, and that is the approach commonly taken, we can compute 144numerical approximations of $\nabla^{p+1}u$ based only on 145the discrete solution $u_h$ that we have computed before. We 146will discuss this in slightly more detail below. This will then 147help us determine which cells have a large $p+1$st derivative, 148and these are then candidates for refining the mesh. 149 150 151<h3> How to deal with hanging nodes in theory </h3> 152 153The methods using triangular meshes mentioned above go to great 154lengths to make sure that each vertex is a vertex of all adjacent 155cells -- i.e., that there are no hanging nodes. This then 156automatically makes sure that we can define shape functions in such a 157way that they are globally continuous (if we use the common $Q_p$ 158Lagrange finite element methods we have been using so far in the 159tutorial programs, as represented by the FE_Q class). 160 161On the other hand, if we define shape functions on meshes with hanging 162nodes, we may end up with shape functions that are not continuous. To 163see this, think about the situation above where the top right cell is 164not refined, and consider for a moment the use of a bilinear finite 165element. In that case, the shape functions associated with the hanging 166nodes are defined in the obvious way on the two small cells adjacent 167to each of the hanging nodes. But how do we extend them to the big 168adjacent cells? Clearly, the function's extension to the big cell 169cannot be bilinear because then it needs to be linear along each edge 170of the large cell, and that means that it needs to be zero on the 171entire edge because it needs to be zero on the two vertices of the 172large cell on that edge. But it is not zero at the hanging node itself 173when seen from the small cells' side -- so it is not continuous. The 174following three figures show three of the shape functions along the 175edges in question that turn out to not be continuous when defined in 176the usual way simply based on the cells they are adjacent to: 177 178<div class="threecolumn" style="width: 80%"> 179 <div class="parent"> 180 <div class="img" align="center"> 181 @image html hanging_nodes_shape_functions_1.png "A discontinuous shape function adjacent to a hanging node" 182 </div> 183 </div> 184 <div class="parent"> 185 <div class="img" align="center"> 186 @image html hanging_nodes_shape_functions_2.png "A discontinuous shape function at a hanging node" 187 </div> 188 </div> 189 <div class="parent"> 190 <div class="img" align="center"> 191 @image html hanging_nodes_shape_functions_3.png "A discontinuous shape function adjacent to a hanging node" 192 </div> 193 </div> 194</div> 195 196 197But we do want the finite element solution to be continuous so that we 198have a “conforming finite element method” where the 199discrete finite element space is a proper subset of the $H^1$ function 200space in which we seek the solution of the Laplace equation. 201To guarantee that the global solution is continuous at these nodes as well, we 202have to state some additional constraints on the values of the solution at 203these nodes. The trick is to realize that while the shape functions shown 204above are discontinuous (and consequently an <i>arbitrary</i> linear combination 205of them is also discontinuous), that linear combinations in which the shape 206functions are added up as $u_h(\mathbf x)=\sum_j U_j \varphi_j(\mathbf x)$ 207can be continuous <i>if the coefficients $U_j$ satisfy certain relationships</i>. 208In other words, the coefficients $U_j$ can not be chosen arbitrarily 209but have to satisfy certain constraints so that the function $u_h$ is in fact 210continuous. 211What these constraints have to look is relatively easy to 212understand conceptually, but the implementation in software is 213complicated and takes several thousand lines of code. On the other 214hand, in user code, it is only about half a dozen lines you have to 215add when dealing with hanging nodes. 216 217In the program below, we will show how we can get these 218constraints from deal.II, and how to use them in the solution of the 219linear system of equations. Before going over the details of the program 220below, you may want to take a look at the @ref constraints documentation 221module that explains how these constraints can be computed and what classes in 222deal.II work on them. 223 224 225<h3> How to deal with hanging nodes in practice </h3> 226 227The practice of hanging node constraints is rather simpler than the 228theory we have outlined above. In reality, you will really only have to 229add about half a dozen lines of additional code to a program like step-4 230to make it work with adaptive meshes that have hanging nodes. The 231interesting part about this is that it is entirely independent of the 232equation you are solving: The algebraic nature of these constraints has nothing 233to do with the equation and only depends on the choice of finite element. 234As a consequence, the code to deal with these constraints is entirely 235contained in the deal.II library itself, and you do not need to worry 236about the details. 237 238The steps you need to make this work are essentially like this: 239- You have to create an AffineConstraints object, which (as the name 240 suggests) will store all constraints on the finite element space. In 241 the current context, these are the constraints due to our desire to 242 keep the solution space continuous even in the presence of hanging 243 nodes. (Below we will also briefly mention that we will also put 244 boundary values into this same object, but that is a separate matter.) 245- You have to fill this object using the function 246 DoFTools::make_hanging_node_constraints() to ensure continuity of 247 the elements of the finite element space. 248- You have to use this object when you copy the local contributions to 249 the matrix and right hand side into the global objects, by using 250 AffineConstraints::distribute_local_to_global(). Up until 251 now, we have done this ourselves, but now with constraints, this 252 is where the magic happens and we apply the constraints to the 253 linear system. What this function does is make sure that the 254 degrees of freedom located at hanging nodes are not, in fact, 255 really free. Rather, they are factually eliminated from the 256 linear system by setting their rows and columns to zero and putting 257 something on the diagonal to ensure the matrix remains invertible. 258 The matrix resulting from this process remains symmetric and 259 positive definite for the Laplace equation we solve here, so we can 260 continue to use the Conjugate Gradient method for it. 261- You then solve the linear system as usual, but at the end of this 262 step, you need to make sure that the degrees of "freedom" located 263 on hanging nodes get their correct (constrained) value so that the 264 solution you then visualize or evaluate in other ways is in 265 fact continuous. This is done by calling 266 AffineConstraints::distribute() immediately after solving. 267 268These four steps are really all that is necessary -- it's that simple 269from a user perspective. The fact that, in the function calls mentioned 270above, you will run through several thousand lines of not-so-trivial 271code is entirely immaterial to this: In user code, there are really 272only four additional steps. 273 274 275<h3> How we obtain locally refined meshes </h3> 276 277The next question, now that we know how to <i>deal</i> with meshes that 278have these hanging nodes is how we <i>obtain</i> them. 279 280A simple way has already been shown in step-1: If you <i>know</i> where 281it is necessary to refine the mesh, then you can create one by hand. But 282in reality, we don't know this: We don't know the solution of the PDE 283up front (because, if we did, we wouldn't have to use the finite element 284method), and consequently we do not know where it is necessary to 285add local mesh refinement to better resolve areas where the solution 286has strong variations. But the discussion above shows that maybe we 287can get away with using the discrete solution $u_h$ on one mesh to 288estimate the derivatives $\nabla^{p+1} u$, and then use this to determine 289which cells are too large and which already small enough. We can then 290generate a new mesh from the current one using local mesh refinement. 291If necessary, this step is then repeated until we are happy with our 292numerical solution -- or, more commonly, until we run out of computational 293resources or patience. 294 295So that's exactly what we will do. 296The locally refined grids are produced using an <i>error estimator</i> 297which estimates the energy error for numerical solutions of the Laplace 298operator. Since it was developed by Kelly and 299co-workers, we often refer to it as the “Kelly refinement 300indicator” in the library, documentation, and mailing list. The 301class that implements it is called 302KellyErrorEstimator, and there is a great deal of information to 303be found in the documentation of that class that need not be repeated 304here. The summary, however, is that the class computes a vector with 305as many entries as there are @ref GlossActive "active cells", and 306where each entry contains an estimate of the error on that cell. 307This estimate is then used to refine the cells of the mesh: those 308cells that have a large error will be marked for refinement, those 309that have a particularly small estimate will be marked for 310coarsening. We don't have to do this by hand: The functions in 311namespace GridRefinement will do all of this for us once we have 312obtained the vector of error estimates. 313 314It is worth noting that while the Kelly error estimator was developed 315for Laplace's equation, it has proven to be a suitable tool to generate 316locally refined meshes for a wide range of equations, not even restricted 317to elliptic only problems. Although it will create non-optimal meshes for other 318equations, it is often a good way to quickly produce meshes that are 319well adapted to the features of solutions, such as regions of great 320variation or discontinuities. 321 322 323 324<h3> Boundary conditions </h3> 325 326It turns out that one can see Dirichlet boundary conditions as just another 327constraint on the degrees of freedom. It's a particularly simple one, 328indeed: If $j$ is a degree of freedom on the boundary, with position 329$\mathbf x_j$, then imposing the boundary condition $u=g$ on $\partial\Omega$ 330simply yields the constraint $U_j=g({\mathbf x}_j)$. 331 332The AffineConstraints class can handle such constraints as well, which makes it 333convenient to let the same object we use for hanging node constraints 334also deal with these Dirichlet boundary conditions. 335This way, we don't need to apply the boundary conditions after assembly 336(like we did in the earlier steps). 337All that is necessary is that we call the variant of 338VectorTools::interpolate_boundary_values() that returns its information 339in an AffineConstraints object, rather than the `std::map` we have used 340in previous tutorial programs. 341 342 343 <h3> Other things this program shows </h3> 344 345 346Since the concepts used for locally refined grids are so important, 347we do not show much other material in this example. The most 348important exception is that we show how to use biquadratic elements 349instead of the bilinear ones which we have used in all previous 350examples. In fact, the use of higher order elements is accomplished by 351only replacing three lines of the program, namely the initialization of 352the <code>fe</code> member variable in the constructor of the main 353class of this program, and the use of an appropriate quadrature formula 354in two places. The rest of the program is unchanged. 355 356The only other new thing is a method to catch exceptions in the 357<code>main</code> function in order to output some information in case the 358program crashes for some reason. This is discussed below in more detail. 359