• No results found

The finite element method is an advanced numerical approach to solving partial differential equations and is typically only taught at the graduate level. This chapter only briefly develops the FEM. The interested reader is referred to the suggested reading at the end of the chapter for further information regarding FEM. The primary focus here is to present a tool (FEniCS) that advanced readers may appreciate later in their academic careers for solving PDEs in more complicated geometries and with greater computational efficiency.

12.2 Why FEM?

The FEM is used to solve partial differential equation such as those that were solved earlier using the finite difference method. Why, we might ask, should we discuss anything beyond the finite difference method? Why do people use FEM instead of finite differences? There are a number of reasons for using FEM, but three reasons are typically given more often than any other:

1. The finite element method is easy to use when the shape of the domain is complex. If we wish to solve Laplace’s equation on a domain that is shaped like the human brain (and this is a real problem in medical imaging), then we need to use FEM because finite difference cannot accurately capture the shape of complex domains.

2. The finite element method is typically easier to extend to higher-order approximations. Imple- menting a 4th- or even 8th-order accurate finite element method is relatively straightforward. This level of accuracy is rarely needed, but it can be a real advantage in some situations like modeling blood flow in the aorta that is nearly turbulent.

3. Rigorous mathematical analysis of FEM is much more extensive than analysis of finite differences.

12.3 Laplace’s Equation

The use of FEniCS and the FEM will only be briefly introduced here through the lens of an example problem. An excellent book [L+12] and a large library of example problems (fenicsproject.org) are available for FEniCS and the interested reader should utilize these resources to gain a much more comprehensive understanding of the FEniCS library and FEM. The FEniCS project is actually a collect of software packages that are used in concert to solve differential equations using FEM. The central software package that to some extent ties everything together is called dolfin. Many of the packages, including dolfin, are written in C++ for faster execution, but wherever necessary, the C++ code has been wrapped so that it can be called from Python. To utilize the various FEniCS packages within a Python code, the first step is to import the dolfin library withfrom dolfin import∗. Since this is the only library that is imported, we do not need to worry about importing multiple objects with the same name.

12.3.1 The Mesh

Whenever we use FEM, we always need to start with a mesh. A mesh is a division of the problem domain into small polyhedral shapes. In two dimensions, we typically divide the domain into triangles or quadrilateral shapes. For simple domains, like squares, rectangles, circles, etc., FEniCS has built in mesh generators that automatically divide the domain into triangles. The function call mesh = UnitSquareMesh(32, 32) divides a unit square into triangles with 32 triangles in each direction. The resulting mesh is shown in figure 12.1. For more complex shapes, a number of software packages are available that provide a CAD-like interface for defining the domain (e.g., our domain might be a mountain bike) and then divide the domain into small polyhedral shapes of a desired type and size. The Cubit software from Sandia National Laboratory is one example.

12.3.2 Discretization

The basic idea behind the FEM is to select a set of mathematical functions called the function space and then determine the exact function on each element that best satisfies the original PDE. The most common function space by a significant margin is polynomial functions of a selected order. While this is a pretty simple idea, the actual implementation is much more difficult. To construct a function space in FEniCS, call V = FunctionSpace(mesh, ’Lagrange’, 2) where ‘Lagrange’ specifies Lagrange polynomials and ‘2’ is the polynomial degree (i.e., quadratic polynomials).

Recall that Laplace’s equation is

∇2u=d

2u dx2+

d2u

dy2 = f(x,y)

and the same boundary conditions as before will be used here (u=sin(πy)on the west boundary, u=0 elsewhere). We begin by integrating both sides of this equation over the entire domain and multiplying both sides of the equation by a ‘test’ function,v, giving:

Z Ω (∇2u)(v)dΩ= Z Ω f(x,y)·v dΩ.

Using integration by parts, this equation becomes:

Z Ω (∇u)(∇v)dΩ+boundary terms= Z Ω f(x,y)·v dΩ.

12.3 Laplace’s Equation 157

Figure 12.1: Triangular mesh from the UnitSquareMesh() function.

This form of the equation is called theweak form, and the boundary terms cancel along all interior boundaries. Along external boundaries, the boundary terms are used to enforce Neumann boundary conditions or they are not present when we have Dirichlet boundary conditions.

12.3.3 Wait! Why are we doing this?

The short answer is to ask a mathematician. The long answer will result when you ask a mathe- matician. The abbreviated answer is that we are trying to find a polynomial approximation ofuon every element. Between elements the approximate solution is continuous, but the derivative is not continuous. By multiplying by a test function, we were able to move one of the two derivatives off of uand ontov. Now we have an equation that we can actually evaluate over the domain to determine an approximate solution. On each element we are trying to determine, essentially, the polynomial coefficients for that element. Since we have many elements, the result is a large linear system where the unknowns are the polynomial coefficients for all the element.

12.3.4 FEniCS implementation

The Python script below uses FEniCS (primarily dolfin) to solve Laplace’s equation on the unit square.

from d o l f i n i m p o r t ∗ # C r e a t e mesh mesh = U n i t S q u a r e M e s h ( 3 2 , 3 2 ) # C r e a t e f u n c t i o n s p a c e V = F u n c t i o n S p a c e ( mesh , ’ L a g r a n g e ’ , 2 ) # D e f i n e b o u n d a r y c o n d i t i o n s u0 = E x p r e s s i o n ( ’ s i n ( p i∗x [ 1 ] )∗( 1−x [ 0 ] ) ’ ) d e f u 0 _ b o u n d a r y ( x , o n _ b o u n d a r y ) : r e t u r n o n _ b o u n d a r y bc = D i r i c h l e t B C ( V , u0 , u 0 _ b o u n d a r y ) # D e f i n e v a r i a t i o n a l p r o b l e m u = T r i a l F u n c t i o n (V) v = T e s t F u n c t i o n (V) f = C o n s t a n t ( 0 . 0 ) a = i n n e r ( g r a d ( u ) , g r a d ( v ) )∗dx L = f∗v∗dx # Compute s o l u t i o n u = F u n c t i o n (V) s o l v e ( a == L , u , bc , s o l v e r _ p a r a m e t e r s ={ ’ l i n e a r _ s o l v e r ’ : ’ cg ’ , ’ p r e c o n d i t i o n e r ’ : ’ i l u ’ } ) # Dump s o l u t i o n t o f i l e i n VTK f o r m a t f i l e = F i l e ( ’ p o i s s o n . pvd ’ ) f i l e << u

The construction of the matrix problem happens when the matrix object,a, is created. The inner product of ‘grad(u)’ and ‘grad(v)’ is same as the weak form equation above. The right-hand-side,L, is just a vector of zeros. The dolfin solve() function solves the linear matrix problem using an iterative method (conjugate gradient) with an incomplete matrix factorization as the preconditioner. The final result is written to a file and can be visualized using Paraview, Visit, or other visualization software packages. Figure 12.2 was generated using Visit from Lawrence Livermore National Laboratory.

Related documents