Chapter 6
Finite Elements

As stated in Section 2. FEM approximates all functions w as
w(x,y) ≃ w0ϕ0(x,y)+ w1ϕ1(x,y) +⋅⋅⋅+ wM -1ϕM-1(x,y)

with finite element basis functions ϕk(x,y) and numbers wk (k = 0,⋅⋅⋅,M -1). The functions ϕk(x,y) is constructed from the triangle Tik, so ϕk(x,y) is a shape function. The finite element space

Vh = {w |w 0ϕ0 + w1ϕ1 + ⋅⋅⋅+ wM -1ϕM -1,wi ∈ ℝ}
is easily created by


     fespace IDspace(IDmesh,<IDFE>) ;

or with pairs of periodic boundary condition in 2d


     fespace IDspace(IDmesh,<IDFE>,
                      periodic=[[la1,sa1],[lb1,sb1],
                                ...
                                [lak,sak],[lbk,sb]]);

and in 3d


     fespace IDspace(IDmesh,<IDFE>,
                      periodic=[[la1,sa1,ta1],[lb1,sb1,tb1],
                                ...
                                [lak,sak,tak],[lbk,sb,tb]]);

where IDspaceis the name of the space (e.g. Vh), IDmeshis the name of the associated mesh and <IDFE>is a identifier of finite element type.

In 2d case, a pair of periodic boundary condition, if [lai,sai],[lbi,sbi]is a pair of int, the 2 labels lai and lbi define the 2 piece of boundary to be in equivalence; If [lai,sai],[lbi,sbi]is a pair of real, then sai and sbi give two common abscissa on the two boundary curve, and two points are identified as one if the two abscissa are equal.

In 2d case, a pair of periodic boundary condition, if [lai,sai,tai],[lbi,sbi,tbi]is a pair of int, the 2 labels lai and lbi define the 2 piece of boundary to be in equivalence;

If [lai,sai,tai],[lbi,sbi,tbi]is a pair of real, then sai,tai and sbi,tbi give two common parameter on the two boundary surface, and two points are identified as one if the two parameter are equal.

Remark, the 2d mesh of the two identified border must be the same, so to be sure, used the parameter fixeborder=truein buildmeshcommand (see 5.1.2) like in example periodic2bis.edp(see 9.7).

As of today, the known types of finite element are:

P0
piecewise constante discontinuous finite element (2d, 3d)
      {    2   ||                                 }
P0h = v ∈ L (Ω )|for all K ∈ Ththere is αK ∈ ℝ : v|K = αK                (6 .1)
P1
piecewise linear continuous finite element (2d, 3d)
      {    1    ||                }
P 1h = v ∈ H (Ω )|∀K ∈ Th  v|K ∈ P 1                      (6 .2)
P1dc
piecewise linear discontinuous finite element
       {         |                }
P1dch = v ∈ L2(Ω) ||∀K ∈ Th v|K ∈ P1
(6.3)

P1b
piecewise linear continuous finite element plus bubble (2d, 3d)
       {     1   ||                        K K  K }
P 1bh = v ∈ H (Ω )|∀K  ∈ Th  v|K ∈ P 1 ⊕ Span{λ0λ1λ 2}
(6.4)

where λiK,i = 0,1,2 are the 3 area coordinate functions of the triangle K

P2
piecewise P2 continuous finite element (2d, 3d),
      {     1   ||                }
P 2h = v ∈ H (Ω )|∀K ∈ Th  v|K ∈ P 2
(6.5)

where P2 is the set of polynomials of ℝ2 of degrees 2.

P2b
piecewise P2 continuous finite element plus bubble,
      {        ||                               }
P2h = v ∈ H1(Ω)|∀K ∈ Th  v|K ∈ P2 ⊕S pan{λK0 λK1λK2}
(6.6)

P2dc
piecewise P2 discontinuous finite element,
       {         |                }
P2dch = v ∈ L2(Ω) ||∀K ∈ Th v|K ∈ P2
(6.7)

RT0
Raviart-Thomas finite element
       {         |                  |       |}
RT0h =  v ∈ H (div)||∀K ∈ Th  v|K(x,y) = ||αKβK + γK ||xy
(6.8)

where by writing div w = ∂w1∕∂x + ∂w2∕∂y,w = (w1,w2),

        {          |           }
H (div) = w ∈ L2(Ω )2||div w ∈ L2(Ω )
and αKKK are real numbers.
P1nc
piecewise linear element continuous at the middle of edge only.

If we get the finite element spaces

          1     2
Xh = {v ∈ H (]0,1[ )|∀K ∈ Th  v|K ∈ P1}
X  = {v ∈ X |v(|||0) = v(|||1),v(|.) = v(|.)}
 ph       h   .     .    0     1
M  = {v ∈ H1(]0,1[2)|∀K ∈ T   v  ∈ P }
  h                      h   |K    2
                                      |      |
Rh = {v ∈ H 1(]0,1[2)2|∀K ∈ Th v|K(x,y) = ||αβK +γK ||xy}
                                       K

when Th is a mesh 10 ×10 of the unit square ]0,1[2, we only write in FreeFem++ as follows:


mesh Th=square(10,10);
fespace Xh(Th,P1);       // scalar FE
fespace Xph(Th,P1,
         periodic=[[2,y],[4,y],[1,x],[3,x]]); // bi-periodic FE
fespace Mh(Th,P2);       // scalar FE
fespace Rh(Th,RT0);      // vectorial FE

where Xh,Mh,Rhexpresses finite element spaces (called FE spaces ) Xh,Mh,Rh, respectively. If we want use FE-functions uh,vh ∈ Xh and ph,qh ∈ Mh and Uh,Vh ∈ Rh , we write in FreeFem++


  Xh uh,vh;
  Xph uph,vph;
  Mh ph,qh;
  Rh [Uxh,Uyh],[Vxh,Vyh];
  Xh[int] Uh(10);  // array of 10 function in Xh
  Rh[int] [Wxh,Wyh](10);  // array of 10 functions in Rh.

The functions Uh,Vh have two components so we have

U  = |||Uxh  and  V  = |||Vxh
 h   Uyh         h   Vyh

6.1 Lagrange finite element

6.1.1 P0-element

For each triangle Tk, the basis function ϕk in Vh(Th,P0)is given by

ϕk(x,y) = 1 if (x,y) ∈ Tk, ϕk(x,y) = 0 if (x,y) ℜ Tk
If we write


Vh(Th,P0);  Vh fh=f (x.y);

then for vertices qki,i = 1,2,3 in Fig. 6.1(a), fh is built as

              n∑t f(qk1)+ f(qk2)+ f(qk3)
fh = fh(x,y) =    ---------3----------ϕk
              k=1
See Fig. 6.3 for the projection of f(x,y) = sin(πx) cos(πy) on Vh(Th,P0)when the mesh This a 4 ×4-grid of [-1,1]2 as in Fig. 6.2.

6.1.2 P1-element


PIC


Figure 6.1: P1 and P2 degrees of freedom on triangle Tk


For each vertex qi, the basis function ϕi in Vh(Th,P1)is given by

         k   k    k
ϕi(x,y) = ai + bix +ciy for (x,y) ∈ Tk,
ϕi(qi) = 1, ϕi(qj) = 0 if i ⇔ j
The basis function ϕk1(x,y) with the vertex qk1 in Fig. 6.1(a) at point p = (x,y) in triangle Tk simply coincide with the barycentric coordinates λ1k (area coordinates) :
          k       -area-of triangle(p,qk2,qk3)
ϕk1(x,y) = λ1(x,y) = area of triangle(qk1,qk2,qk3)
If we write


Vh(Th,P1); Vh fh=g(x.y);

then

              n∑v    i
fh = fh(x,y) =    f(q)ϕi(x,y)
              i=1
See Fig. 6.4 for the projection of f(x,y) = sin(πx) cos(πy) into Vh(Th,P1).


PIC

Figure 6.2: Test mesh Th for projection

PIC

Figure 6.3: projection to Vh(Th,P0)


6.1.3 P2-element

For each vertex or midpoint qi. the basis function ϕi in Vh(Th,P2)is given by

ϕi(x,y) = aki + bkix +ckiy+ dkix2 + ekixy+ ffj y2 for (x,y) ∈ Tk,
   i          j
ϕi(q ) = 1, ϕi(q ) = 0 if i ⇔ j
The basis function ϕk1(x,y) with the vertex qk1 in Fig. 6.1(b) is defined by the barycentric coordinates:
          k       k
ϕk1(x,y) = λ1(x,y)(2λ1(x,y) - 1)
and for the midpoint qk2
            k     k
ϕk2(x,y) = 4λ 1(x,y)λ4(x,y)
If we write


Vh(Th,P2); Vh fh=f (x.y);

then

             ∑M    i
fh = fh(x,y) =   f (q )ϕi(x,y) (sum mation over all vetex or m idpoint)
              i=1
See Fig. 6.5 for the projection of f(x,y) = sin(πx) cos(πy) into Vh(Th,P2).


PIC

Figure 6.4: projection to Vh(Th,P1)

PIC

Figure 6.5: projection to Vh(Th,P2)


6.2 P1 Nonconforming Element

Refer to [23] for details; briefly, we now consider non-continuous approximations so we shall lose the property

           1
wh ∈ Vh ⊂ H (Ω)
If we write


Vh(Th,P1nc); Vh fh=f (x.y);

then

              n∑v
fh = fh(x,y) =    f(mi)ϕi(x,y) (summ ation over all midpoin t)
              i=1
Here the basis function ϕi associated with the midpoint mi = (qki + qki+1)2 where qki is the i-th point in Tk, and we assume that j + 1 = 0 if j = 3:
         k   k    k
ϕi(x,y) = ai + bix +ciy for (x,y) ∈ Tk,
ϕi(mi) = 1, ϕi(mj) = 0 if i ⇔ j

Strictly speaking ∂ϕi∕∂x,∂ϕi∕∂y contain Dirac distribution ρδ∂Tk. The numerical calculations will automatically ignore them. In [23], there is a proof of the estimation

(||n∑v ∫                 )||1∕2
||||(      |∇w - ∇wh|2dx dy||||)  = O (h)
 k=1 Tk

The basis functions ϕk have the following properties.

  1. For the bilinear form a defined in (2.6) satisfy
    a(ϕi,ϕi) > 0,   a (ϕi,ϕj) ≤ 0 if i ⇔ j
∑nv
   a(ϕi,ϕk) ≥ 0
k=1
  2. f 0 uh 0
  3. If i j, the basis function ϕi and ϕj are L2-orthogonal:
    ∫
   ϕiϕjdxdy = 0   if i ⇔ j
 Ω
    which is false for P1-element.

See Fig. 6.6 for the projection of f(x,y) = sin(πx) cos(πy) into Vh(Th,P1nc). See Fig. 6.6 for the projection of f(x,y) = sin(πx) cos(πy) into Vh(Th,P1nc).


PIC

Figure 6.6: projection to Vh(Th,P1nc)

PIC

Figure 6.7: projection to Vh(Th,P1b)


6.3 Other FE-space

For each triangle Tk ∈ Th, let λk1(x,y),λk2(x,y),λk3(x,y) be the area cordinate of the triangle (see Fig. 6.1), and put

βk(x,y) = 27λk1(x,y)λk2(x,y)λk3(x,y)
(6.9)

called bubble function on Tk. The bubble function has the feature:

  1. βk(x,y) = 0 if (x,y) ∈ ∂Tk.
  2. βk(qkb) = 1 where qkb is the barycenter  k  k  k
q1+q32+q3-.

If we write


Vh(Th,P1b); Vh fh=f (x.y);

then

             ∑nv             ∑nt
fh = fh(x,y) =   f (qi)ϕi(x,y)+    f(qkb)βk(x,y)
              i=1             k=1
See Fig. 6.7 for the projection of f(x,y) = sin(πx) cos(πy) into Vh(Th,P1b).

6.4 Vector valued FE-function

Functions from ℝ2 to ℝN with N = 1 is called scalar function and called vector valued when N > 1. When N = 2


     fespace Vh(Th,[P0,P1]) ;

make the space

Vh = {w = (w1,w 2)|w1 ∈ Vh(Th,P0),w2 ∈ Vh(Th,P 1)}

6.4.1 Raviart-Thomas element

In the Raviart-Thomas finite element RT0h, the degree of freedom are the fluxes across edges e of the mesh, where the flux of the function f : ℝ2-→ℝ2 is ef.ne, ne is the unit normal of edge e.

This implies a orientation of all the edges of the mesh, for example we can use the global numbering of the edge vertices and we just go from small to large numbers.

To compute the flux, we use a quadrature with one Gauss point, the middle point of the edge. Consider a triangle Tk with three vertices (a,b,c). Let denote the vertices numbers by ia,ib,ic, and define the three edge vectors e1,e2,e3 by sgn(ib -ic)(b -c), sgn(ic -ia)(c -a), sgn(ia -ib)(a -b),

We get three basis functions,

ϕk=  sgn-(ib --ic)(x- a), ϕk = sgn(ic --ia)(x - b ), ϕk = sgn(ia-- ib)(x - c),
 1     2|Tk|            2     2 |Tk|            3      2|Tk|
(6.10)

where |Tk|is the area of the triangle Tk. If we write


Vh(Th,RT0); Vh [f1h,f2h]=[f 1(x.y),f 2(x,y)];

then

              ∑nt ∑6
fh = fh(x,y) =      niljl|eil|fjl(mil)ϕiljl
              k=1l=1
where niljl is the jl-th component of the normal vector nil,
             {                }
{m1,m2,m 3} =  b-+c-,a+-c,b-+-a
                2    2     2
and il = {1,1,2,2,3,3},jl = {1,2,1,2,1,2}with the order of l.

PIC


Figure 6.8: normal vectors of each edge


Example 6.1


mesh Th=square(2,2);
fespace Xh(Th,P1);
fespace Vh(Th,RT0);
Xh uh,vh;
Vh [Uxh,Uyh];
[Uxh,Uyh] = [sin(x),cos(y)];    // ok vectorial FE function
vh= x^2+y^2;   // vh
Th = square(5,5);  // change the mesh
// Xh is unchange
uh = x^2+y^2;  // compute on the new Xh
Uxh = x;     // error: impossible to set only 1 component
          // of a vector FE function.
vh = Uxh;   // ok
// and now uh use the 5x5 mesh
// but the fespace of vh is alway the 2x2 mesh
plot(uh,ps="onoldmesh.eps");   // figure 6.9
uh = uh;  // do a interpolation of vh (old) of 5x5 mesh
             // to get the new vh on 10x10 mesh.
plot(uh,ps="onnewmesh.eps");  // figure 6.10
vh([x-1/2,y])= x^2 + y^2;   // interpolate vh = ((x - 12)2 + y2)


PIC

Figure 6.9: vh Iso on mesh 2 ×2

PIC

Figure 6.10: vh Iso on mesh 5 ×5


To get the value at a point x = 1,y = 2 of the FE function uh, or [Uxh,Uyh],one writes


   real value;
   value = uh(2,4);        // get value= uh(2,4)
   value = Uxh(2,4);       // get value= Uxh(2,4)
    // ------ or ------
   x=1;y=2;
   value = uh;        // get value= uh(1,2)
   value = Uxh;       // get value= Uxh(1,2)
   value = Uyh;       // get value= Uyh(1,2).

To get the value of the array associated to the FE function uh, one writes


   real value = uh[][0] ;  // get the value of degree of freedom 0
   real maxdf = uh[].max;  // maximum value of degree of freedom
   int size = uh.n;  // the number of degree of freedom
   real[int] array(uh.n)= uh[];  // copy the array of the function uh

Note 6.1 For a none scalar finite element function [Uxh,Uyh]the two array Uxh[]and Uyh[]are the same array, because the degree of freedom can touch more than one component.

6.5 A Fast Finite Element Interpolator

In practice one may discretize the variational equations by the Finite Element method. Then there will be one mesh for Ω1 and another one for Ω2. The computation of integrals of products of functions defined on different meshes is difficult. Quadrature formulae and interpolations from one mesh to another at quadrature points are needed. We present below the interpolation operator which we have used and which is new, to the best of our knowledge. Let Th0 = kTk0,Th1 = kTk1 be two triangulations of a domain Ω. Let

    i     0  i
V (T h) = {C (Ωh) : f|Tik ∈ P 0}, i = 0,1
be the spaces of continuous piecewise affine functions on each triangulation.

Let f ∈ V(Th0). The problem is to find g ∈ V(Th1) such that

g(q ) = f(q) ∀q vertex of T1h
Although this is a seemingly simple problem, it is difficult to find an efficient algorithm in practice. We propose an algorithm which is of complexity N1 log N0, where Ni is the number of vertices of Thi, and which is very fast for most practical 2D applications.

Algorithm
The method has 5 steps. First a quadtree is built containing all the vertices of mesh Th0 such that in each terminal cell there are at least one, and at most 4, vertices of Th0 .
For each q1, vertex of Th1 do:

Step 1
Find the terminal cell of the quadtree containing q1.
Step 2
Find the the nearest vertex qj0 to q1 in that cell.
Step 3
Choose one triangle Tk0 ∈ Th0 which has qj0 for vertex.
Step 4
Compute the barycentric coordinates {λj}j=1,2,3 of q1 in Tk0.
Step 5
Calculate g(q1) on Tk0 by linear interpolation of f:
   1    ∑        0
g(q ) =     λjf(qj)
       j=1,2,3
End
 


PIC


Figure 6.11: To interpolate a function at q0 the knowledge of the triangle which contains q0 is needed. The algorithm may start at q1 ∈ Tk0 and stall on the boundary (thick line) because the line q0q1 is not inside Ω. But if the holes are triangulated too (doted line) then the problem does not arise.


Two problems need to be solved:

Note 6.2 Step 3 requires an array of pointers such that each vertex points to one triangle of the triangulation.

Note 6.3 The operator = is the interpolation operator of FreeFem++ , The continuous finite functions are extended by continuity to the outside of the domain. Try the following example


mesh Ths= square(10,10);
 mesh Thg= square(30,30,[x⋆3-1,y⋆3-1]);
 plot(Ths,Thg,ps="overlapTh.eps",wait=1);
fespace Ch(Ths,P2); fespace Dh(Ths,P2dc);
fespace Fh(Thg,P2dc);
Ch us= (x-0.5)⋆(y-0.5);
Dh vs= (x-0.5)⋆(y-0.5);
Fh ug=us,vg=vs;
plot(us,ug,wait=1,ps="us-ug.eps");  // see figure 6.12
plot(vs,vg,wait=1,ps="vs-vg.eps");  // see figure 6.13


PIC

Figure 6.12: Extension of a continuous FE-function

PIC

Figure 6.13: Extention of discontinuous FE-function


6.6 Keywords: Problem and Solve

For FreeFem++ a problem must be given in variational form, so we need a bilinear form a(u,v) , a linear form (f,v), and possibly a boundary condition form must be added.


problem P(u,v) =
     a(u,v) - (f,v)
     + (boundary condition);

Note 6.4 When you want to formulate the problem and to solve it in the same time, you can use the keywork solve.

6.6.1 Weak form and Boundary Condition

To present the principles of Variational Formulations or also called weak forms fr the PDEs, let us take a model problem : a Poisson equation with Dirichlet and Robin Boundary condition .

The problem is: Find u a real function defined on domain Ω of ℝ2 such that

                             ∂u-
- ∇.(ν∇u ) = f, in  Ω,  au + ν∂n = b  on  Γ r, u = g on  Γ d
(6.11)

where

Note 6.5 This problem, we can be a classical Neumann boundary condition if a is 0, and if Γd is empty. In this case the function is defined just by derivative, so this defined too a constant (if u is a solution then u + 1 is also a solution).

Let v a regular test function null on Γd , by integration par part we get

 ∫               ∫             ∫         ∫
-   ∇.(ν∇u)vdω =    ν∇v.∇udω =    fvdω -    vν∂udγ,
   Ω              Ω              Ω        Γ   ∂n
(6.12)

where v.u = ∂u
∂x∂v
∂x + ∂u
∂y∂v
∂y , and where n is the unitary outside normal of Ω.

Now we note that ν∂u∂n- = -au + g on Γr and v = 0 on Γd and Ω = Γd Γn thus

 ∫     ∂u   ∫       ∫
-    vν∂n-=    auv-    bv
   ∂Ω         Γr       Γr

The problem become:

Find u ∈ Vg = {v ∈ H1(Ω)∕v = g on Γd}such that

∫             ∫          ∫        ∫
   ν∇v.∇ud ω +    auvdγ =   f vdω +    bvdγ,  ∀v ∈ V0
 Ω             Γr         Ω         Γr
(6.13)

where V0 = {v ∈ H1(Ω)∕v = 0 on Γd}

The problem (6.13) is generally well posed if we do not have only Neumann boundary condition ( ie. Γd = and a = 0).

Note 6.6 If we have only Neumann boundary condition, then solution is not unique and linear algebra tells us that the right hand side must be orthogonal to the kernel of the operator. Here the problem is defined to a constant, and since 1 ∈ V0 one way of writing the compatibility condition is: Ωf+ Γband a way to fix the constant is to solve for u ∈ H1(Ω) such that:

∫                    ∫         ∫                1
  εuvdω + ν∇v.∇ud ω =   f vd ω+    bvd γ,  ∀v ∈ H (Ω )
 Ω                     Ω         Γr
(6.14)

where ε is a small parameter ( ~ 10-10 ).

Remark that if the solution is of order 1ε then the compatibility condition is unsatisfied, otherwise we get the solution such that Ωu = 0.

In FreeFem++, the problem (6.13) become


  problem Pw(u,v) =
       int2d(Th)( nu⋆ ( dx(u)⋆dx(u) +  dy(u)⋆dy(u)))   // Ω νv.u
     + int1d(Th,gn)( a ⋆ u⋆v )                         // Γ r auv
     - int2d(Th)(f⋆v)                                  // Ω fv
     - int1d(Th,gn)( b ⋆ v )                           // Γ r bv
     + on(gd)(u= g) ;                                  // u = g on Γd

where This a mesh of the domain Ω, and gdand gnare respectively the boundary label of boundary Γd and Γn.

6.7 Parameters affecting solveand problem

The parameters are FE functions real or complex, the number n of parameters is even (n = 2 *k), the k first function parameters are unknown, and the k last are test functions.

Note 6.7 If the functions are a part of vectoriel FE then you must give all the functions of the vectorial FE in the same order (see laplaceMixte problem for example).

Note 6.8 Don’t mix complex and real parameters FE function.

Bug: 1 The mixing of fespace with different periodic boundary condition is not implemented. So all the finite element spaces used for test or unknown functions in a problem, must have the same type of periodic boundary condition or no periodic boundary condition. No clean message is given and the result is impredictible, Sorry.

The parameters are:

solver=
LU, CG, Crout,Cholesky,GMRES,sparsesolver, UMFPACK...

The default solver is sparsesolver( it is equal to UMFPACKif not other sparce solver is defined) or is set to LUif no direct sparse solver is available. The storage mode of the matrix of the underlying linear system depends on the type of solver chosen; for LU the matrix is sky-line non symmetric, for Crout the matrix is sky-line symmetric, for Cholesky the matrix is sky-line symmetric positive definite, for CGthe matrix is sparse symmetric positive, and for GMRES, sparsesolver or UMFPACKthe matrix is just sparse.

eps=
a real expression. ε sets the stopping test for the iterative methods like CG. Note that if ε is negative then the stopping test is:
||Ax - b|| < |ε|
if it is positive then the stopping test is
||Ax - b|| <--|ε|----
          ||Ax0 - b||
init=
boolean expression, if it is false or 0 the matrix is reconstructed. Note that if the mesh changes the matrix is reconstructed too.
precon=
name of a function (for example P) to set the preconditioner. The prototype for the function P must be


    func real[int]  P(real[int] & xx) ;
tgv=
Huge value (1030) used to implement Dirichlet boundary conditions.
tolpivot=
set the tolerence of the pivot in UMFPACK (10-1) and, LU, Crout, Cholesky factorisation (10-20).
tolpivotsym=
set the tolerence of the pivot sym in UMFPACK
strategy=
set the integer UMFPACK strategy (0 by default).

6.8 Problem definition

Below vis the unknown function and wis the test function.

After the ”=” sign, one may find sums of:

Note 6.9

Important: it is not possible to write in the same integral the linear part and the bilinear part such as in int1d(Th)( K⋆v⋆w - f⋆w) .

6.9 Numerical Integration

Let D be a N-dimensional bounded domain. For an arbitrary polynomials f of degree r, if we can find particular points ξj,j = 1,⋅⋅⋅,J in D and constants ωj such that

∫        ∑L
   f(x ) =   cℓf(ξℓ)                                (6.15 )
 D       ℓ=1
then we have the error estimation (see Crouzeix-Mignot (1984)), and then there exists a constant C > 0 such that,
|                  |
|||∫       ∑L        |||       r+1
||  f (x )-    ωℓf(ξℓ)||≤ C |D |h                             (6.16 )
| D       ℓ=1       |
for any function r + 1 times continuously differentiable f in D, where h is the diameter of D and |D|its measure (a point in the segment [qiqj] is given as
{(x,y)|x = (1 - t)qix + tqjx,y = (1- t)qiy + tqjy,0 ≤ t ≤ 1}).

For a domain Ωh = k=1ntTk,Th = {Tk}, we can calculate the integral over Γh = Ωh by

∫
   f(x)ds  =  int 1d(T h)(f )
 Γh
           =  int 1d(T h,qf e=⋆) (f)

           =  int 1d(T h,qf orde r=⋆) (f)
where * stands for the name of the quadrature formula or the precision (order) of the Gauss formula.






L (qfe=) qforder= point in [qiqj](= t) ω     exact on Pk,k =












1 qf1pE 2 12 |qiqj| 1






2 qf2pE 3 (1 ±√----
 1 ∕3)2 |qiqj|2 3






3 qf3pE 6 (1 ±√----
 3 ∕5)2 (518)|qiqj| 5
12 (818)|qiqj|






4 qf4pE 8 (1 ±√ -----√--
--525+70-30
    35)2.    √--
18--30
  72|qiqj| 7
(1 ±√ -----√--
--525-70-30
    35)2.    √--
18+-30
  72|qiqj|






5 qf5pE 10 (1 ± √245+14√70
----21----)2      √--
322-11830070|qiqj| 9
12 62425-|qiqj|
(1 ± √245-14√70
----21----)2 322+13√70
--1800--|qiqj|






2 qf1pElump 2 -1 |qiqj|2 1
+1 |qiqj|2







where |qiqj|is the length of segment qiqj. For a part Γ1 of Γh with the label “1”, we can calculate the integral over Γ1 by

∫
   f(x,y)ds  =  i nt1d (Th, 1)(f )
 Γ1
            =  i nt1d (Th, 1,qf e=qf 2pE) (f)
The integral over Γ1,Γ3 are given by
∫
      f(x,y)ds = i nt1d (Th, 1,3) (f)
 Γ1∪Γ3

For each triangule Tk = [qk1qk2qk3] , the point P(x,y) in Tk is expressed by the area coordinate as P(ξ,η):

      ||    k1  k1 ||       ||           ||       ||    k1  k1 ||       ||    k1  k1 ||
      |||1  qxk2 qyk2 |||       |||1   xk2  yk2 |||       |||1  qx  qy  |||       |||1  qxk  qyk  |||
|Tk| = |||1 qx  qy  |||  D1 = |||1  qx  qy  |||  D2 = |||1   x   y  |||  D3 = |||1  qx2 qy2 |||
      |1  qkx3 qky3 |       |1  qkx3 qky3 |       |1  qkx3 qky3 |       |1   x   y  |
ξ = D1∕|Tk|    η = D2∕|Tk|    th en 1 - ξ - η = D 3∕|Tk|
For a domain Ωh = k=1ntTk,Th = {Tk}, we can calculate the integral over Ωh by
∫
   f(x,y)  =  int 2d(T h)(f )
 Ωh
           =  int 2d(T h,qf t=⋆) (f)
           =  int 2d(T h,qf orde r=⋆) (f)
where * stands for the name of quadrature formula or the order of the Gauss formula.






L qft= qforder= point in Tk ω    degree of exact












1 qf1pT 2 (1 1)
 3,3 |Tk| 1






3 qf2pT 3 (   )
 12,12 |Tk|3 2
(1  )
 2,0 |Tk|3
(   )
0, 12 |Tk|3






7 qf5pT 6 (1 1)
 3,3 0.225|Tk| 5
(  √--   √--)
 6-2115,6-2115     √--
(155-121005)|Tk|
(6-√15 9+2√15)
   21 ,  21 (155-√15)|Tk|
   1200
(   √--   √--)
 9+2-15,6--15
   21     21     √--
(155--15)|Tk|
   1200
(6+√15 6+√15)
  21  , 21 (155+√15)|Tk|
   1200
(  √--    √--)
 6+-15,9-2-15
   21    21     √--
(155+-15)|Tk|
   1200
(9-2√15 6+√15)
 --21--,--21-- (155+√15)|T |
---1200--k-






3 qf1pTlump (0, 0) |Tk|3 1
(1, 0) |Tk|3
(0, 1) |Tk|3






9 qf2pT4P1 (   )
 14,34 |Tk|12 1
(   )
 3,1
 4 4 |Tk|12
(  1)
0, 4 |Tk|12
(   )
0, 3
   4 |Tk|12
(1  )
 4,0 |Tk|12
(   )
 3,0
 4 |Tk|12
(1 1)
 4,4 |Tk|6
(   )
 14,12 |Tk|6
(1 1)
 2,4 |Tk|6






15 qf7pT 8 see [38] for detail 7






21 qf9pT 10 see [38] for detail 9







Note 6.10 By default, we use the formula which is exact for polynomes of degrees 5 on triangles or edges (in bold in two tables).

6.10 Variational Form, Sparse Matrix, PDE Data Vector

First, it is possible to define variational forms, and use this forms to build matrix and vector to make very fast script (4 times faster here).

For example solve the Thermal Conduction problem of section 3.4.

The variational formulation is in L2(0,T; H1(Ω)); we shall seek un satisfying

            ∫   n   n-1             ∫
∀w ∈ V 0;      u---u---w + κ∇un ∇w )+   α(un - uue)w = 0
             Ω    δt                  Γ

where V0 = {w ∈ H1(Ω)∕w|Γ24 = 0}.

So the to code the method with the matrices A = (Aij), M = (Mij), and the vectors un,bn,b,b,bcl ( notation if w is a vector then wi is a component of the vector).

                                                {
 n    -1 n      ′         n-1                n    b”i  if i ∈ Γ 24
u  = A  b ,    b = b0 + Mu   ,  b” = ν∞bcl, bi =   b′  else if ℜ Γ 24
                                                    i
(6.17)

Where with ν = tgv = 1030 :

        (
        |||{  ∫              ν∞      ∫          if i ∈ Γ 24,andj = i
 Aij =  |||    w  w ∕dt +k(∇w  .∇w ) +    αw  w  else if i ℜ Γ ,orj ⇔ i      (6.18 )
        (   Ω  j i         j   i    Γ13   j i           24
        (|     ν       if i ∈ Γ ,andj = i
        ||{  ∫   ∞            24
Mij  =  |||(    wjwi ∕dt  else if i ℜ Γ 24,orj ⇔ i                             (6.19 )
        ∫   Ω
 b   =      αu  w                                                       (6.20 )
  0,i      Γ13   ue  i
         0
 bcl =  u   the initial data                                              (6.21 )


// file thermal-fast.edp in examples++-tutorial
func fu0 =10+90⋆x/6;
func k = 1.8⋆(y<0.5)+0.2;
real ue = 25. , alpha=0.25, T=5, dt=0.1 ;
mesh Th=square(30,5,[6⋆x,y]);
fespace Vh(Th,P1);
Vh u0=fu0,u=u0;

Create three variational formulation, and build the matrices A,M.


varf vthermic (u,v)= int2d(Th)(u⋆v/dt + k⋆(dx(u) ⋆ dx(v) + dy(u) ⋆ dy(v)))
  +  int1d(Th,1,3)(alpha⋆u⋆v)
  + on(2,4,u=1);
varf vthermic0(u,v) =   int1d(Th,1,3)(alpha⋆ue⋆v);
varf vMass (u,v)= int2d(Th)( u⋆v/dt)  + on(2,4,u=1);
real tgv = 1e30;
matrix A= vthermic(Vh,Vh,tgv=tgv,solver=CG);
matrix M= vMass(Vh,Vh);

Now, to build the right hand size we need 4 vectors.


real[int]  b0  = vthermic0(0,Vh);  // constant part of the RHS
real[int]  bcn = vthermic(0,Vh);  // tgv on Dirichlet boundary node ( !=0 )
// we have for the node i : i ∈ Γ24 bcn[i] 0
real[int]  bcl=tgv⋆u0[];  // the Dirichlet boundary condition part

Note 6.11 The boundary condition is implemented by penalization and vector bcn contains the contribution of the boundary condition u=1 , so to change the boundary condition, we have just to multiply the vector bc[] by the current value f of the new boundary condition term by term with the operator .⋆. Section 9.6.2 Examples++-tutorial/StokesUzawa.edp gives a real example of using all this features.

And the new version of the algorithm:


ofstream ff("thermic.dat");
for(real t=0;t<T;t+=dt){
    real[int] b = b0 ;  // for the RHS
    b += M⋆u[];  // add the the time dependant part
     // lock boundary part:
    b = bcn ? bcl  : b ;  // do i: b[i] = bcn[i] ? bcl[i] : b[i] ;
    u[] = A^-1⋆b;
    ff << t <<" "<<u(3,0.5)<<endl;
    plot(u);
}
for(int i=0;i<20;i++)
  cout<<dy(u)(6.0⋆i/20.0,0.9)<<endl;
plot(u,fill=true,wait=1,ps="thermic.eps");

Note 6.12 The functions appearing in the variational form are formal; they must be declared but not necessarily defined, the only important think in the order in the parameter list, like in


 varf vb1([u1,u2],q) = int2d(Th)( (dy(u1)+dy(u2)) ⋆q) + int2d(Th)(1⋆q);
 varf vb2([v1,v2],p) = int2d(Th)( (dy(v1)+dy(v2)) ⋆p) + int2d(Th)(1⋆p);

To build matrix A from the bilinear part the the variational form a of type varfdo simply


  A = a(Vh,Wh [, ...] );
  // where Vh is "unkown fespace" with a correct number of component
  // where Wh is "test fespace" with a correct number of component

The possible named parameter " [, ... ] "of the construction are

solver=
LU, CG, Crout, Cholesky, GMRES, sparsesolver, UMFPACK...

The default solver is GMRES. The storage mode of the matrix of the underlying linear system depends on the type of solver chosen; for LU the matrix is sky-line non symmetric, for Crout the matrix is sky-line symmetric, for Choleskythe matrix is sky-line symmetric positive definite, for CGthe matrix is sparse symmetric positive, and for GMRES, sparsesolver or UMFPACK the matrix is just sparse.

factorize =
if true then do the matrix factorization for LU, Cholesky or Crout, the default value is false.
eps=
a real expression. ε sets the stopping test for the iterative methods like CG. Note that if ε is negative then the stopping test is:
||Ax - b|| < |ε|
if it is positive then the stopping test is
             |ε|
||Ax - b|| <--------
          ||Ax0 - b||
precon=
name of a function (for example P) to set the precondioner. The prototype for the function Pmust be


    func real[int]  P(real[int] & xx) ;
tgv=
Huge value (1030) used to implement Dirichlet boundary conditions.
tolpivot=
set the tolerence of the pivot in UMFPACK (10-1) and, LU, Crout, Cholesky factorisation (10-20).
tolpivotsym=
set the tolerence of the pivot sym in UMFPACK
strategy=
set the integer UMFPACK strategy (0 by default).

Note 6.13 The line of the matrix corresponding to the space Wh and the column of the matrix corresponding to the space Vh.

To build the dual vector b (of type real[int]) from the linear part of the variational form a do simply


  real b(Vh.ndof);
  b = a(0,Vh);

A first example to compute the area of each triangle K of mesh Th, just do:


   fespace Nh(Th,P0);  // the space function contant / triangle
   Nh areaK;
   varf varea(unused,chiK) =  int2d(Th)(chiK);
   etaK[]= varea(0,Ph);

Effectively, the basic functions of space Nh, are the characteristic function of the element of Th, and the numbering is the numeration of the element, so by construction:

        ∫       ∫

etaK[i] =   1|Ki =  Ki 1;

Now, we can use this to compute error indicator like in examples AdaptResidualErrorIndicator.edpin directory examples++-tutorial.

First to compute a continuous approximation to the function h ”density mesh size” of the mesh Th.


   fespace Vh(Th,P1);
   Vh h ;
   real[int]  count(Th.nv);  varf vmeshsizen(u,v)=intalledges(Th,qfnbpE=1)(v);
   varf vedgecount(u,v)=intalledges(Th,qfnbpE=1)(v/lenEdge);
    // computation of the mesh size
    // -----------------------------
   count=vedgecount(0,Vh);  // number of edge / vertex
   h[]=vmeshsizen(0,Vh);  // sum length edge / vertex
   h[]=h[]./count;  // mean lenght edge / vertex

To compute error indicator for Poisson equation :

     ∫                ∫
η  =    h2|(f + Δu )|2 +   h |[∂uh ]|2
  K    K K       h      ∂K e  ∂n
where hK is size of the longest edge ( hTriangle), he is the size of the current edge ( lenEdge), n the normal.


   fespace Nh(Th,P0);  // the space function contant / triangle
   Nh etak;
   varf vetaK(unused,chiK) =
       intalledges(Th)(chiK⋆lenEdge⋆square(jump(N.x⋆dx(u)+N.y⋆dy(u))))
      +int2d(Th)(chiK⋆square(hTriangle⋆(f+dxx(u)+dyy(u))) );
   etak[]= vetaK(0,Ph);

We add automatic expression optimization by default, if this optimization creates problems, it can be removed with the keyword optimizeas in the following example :


varf a(u1,u2)= int2d(Th,optimize=false)(  dx(u1)⋆dx(u2) + dy(u1)⋆dy(u2) )
                    +  on(1,2,4,u1=0)  +  on(3,u1=1) ;

Remark, it is all possible to build interpolation matrix, like in the following example:


mesh  TH = square(3,4);
mesh  th = square(2,3);
mesh  Th = square(4,4);
fespace VH(TH,P1);
fespace Vh(th,P1);
fespace Wh(Th,P1);
matrix B= interpolate(VH,Vh);   // build interpolation matrix
Vh->VH matrix BB= interpolate(Wh,Vh);   // build interpolation
matrix  Vh->Wh 

and after some operations on sparse matrices are available for example


  int N=10;
  real [int,int] A(N,N);   // a full matrix
  real [int] a(N),b(N);
  A =0;
  for (int i=0;i<N;i++)
    {
      A(i,i)=1+i;
      if(i+1 < N)    A(i,i+1)=-i;
      a[i]=i;
    }
  b=A⋆b;
  cout << "xxxx\n";
  matrix sparseA=A;
  cout << sparseA << endl;
  sparseA = 2⋆sparseA+sparseA';
  sparseA = 4⋆sparseA+sparseA⋆5;  //
  matrix sparseB=sparseA+sparseA+sparseA; ;
  cout << "sparseB = " << sparseB(0,0) << endl;

6.11 Interpolation matrix

This becomes possible to store the matrix of a linear interpolation operator from a finite element space Vh to Wh with interpolatefunction. Note that the continuous finite functions are extended by continuity to the outside of the domain.

The named parameter of function interpolateare:

inside=
set true to create zero-extension.
t=
set true to get the transposed matrix
op=
set an integer written below
0
the default value and interpolate of the function
1
interpolate the x
2
interpolate the y

. .

Example 6.2 (mat_interpol.edp)  


mesh Th=square(4,4);
mesh Th4=square(2,2,[x⋆0.5,y⋆0.5]);
plot(Th,Th4,ps="ThTh4.eps",wait=1);
fespace Vh(Th,P1);     fespace Vh4(Th4,P1);
fespace Wh(Th,P0);     fespace Wh4(Th4,P0);
matrix IV= interpolate(Vh,Vh4);  // here the function is
// exended by continuity
cout << " IV Vh<-Vh4 " << IV << endl;
Vh v, vv;          Vh4 v4=x⋆y;
v=v4;              vv[]= IV⋆v4[];
// here v == vv =>
real[int]  diff= vv[] - v[];
cout << " || v - vv || = " <<  diff.linfty << endl;
assert( diff.linfty<= 1e-6);
matrix IV0= interpolate(Vh,Vh4,inside=1);  // here the fonction is
// exended by zero
cout << " IV Vh<-Vh4 (inside=1)  " << IV0 << endl;
matrix IVt0= interpolate(Vh,Vh4,inside=1,t=1);
cout << " IV Vh<-Vh4^t (inside=1)  " << IVt0 << endl;
matrix IV4t0= interpolate(Vh4,Vh);
cout << " IV Vh4<-Vh^t  " << IV4t0 << endl;
matrix IW4= interpolate(Wh4,Wh);
cout << " IV Wh4<-Wh  " << IW4  << endl;
matrix IW4V= interpolate(Wh4,Vh);
cout << " IV Wh4<-Vh  " << IW4  << endl;

6.12 Finite elements connectivity

Here, we show how get the informations of a finite element space Wh(Tn,*), where “*” denotes P1, P2, P1nc, etc.

See the following for an example:

Example 6.3 (FE.edp)


mesh Th=square(5,5);
fespace Wh(Th,P2);
cout << " nb of degree of freedom           : " << Wh.ndof << endl;
cout << " nb of degree of freedom / ELEMENT : " << Wh.ndofK << endl;
 int k= 2;   // element 2
 int kdf= Wh.ndofK ;
 cout << " df of element " << k << ":" ;
 for (int i=0;i<kdf;i++)
    cout << Wh(k,i) << " ";
 cout << endl;

and the output is:


 Nb Of Nodes = 121
 Nb of DF = 121
 FESpace:Gibbs: old skyline = 5841  new skyline = 1377
 nb of degree of freedom           : 121
 nb of degree of freedom / ELEMENT : 6
 df of element 2:78 95 83 87 79 92