Chapter 12
Add new finite element
12.1 Some notation
For a function f taking value in
N,N = 1,2,
, we define the finite element approximation Πhf of
f. Let us denote the number of the degrees of freedom of the finite element by NbDoF. Then the
i-th base ωiK (i = 0,
,NbDoF -1) of the finite element space has the j-th component ωijK for
j = 0,
,N -1.
The operator Πh is called the interpolator of the finite element. We have the identity ωiK = ΠhωiK.
Formally, the interpolator Πh is constructed by the following formula:
 | (12.1) |
where Pp is a set of npPi points,
In the formula (12.1), the list pk,jk,ik depend just on the type of finite element (not on the element), but the
coefficient αk can be depending on the element.
Example 1: classical scalar Lagrange finite element, first we have kPi = npPi = NbOfNodeand
- Pp is the point of the nodal points
- the αk = 1, because we take the value of the function at the point Pk
- pk = k , jk = k because we have one node per function.
- jk = 0 because N = 1
Example 2: The Raviart-Thomas finite element:
 | (12.2) |
The degree of freedom are the flux throw an edge 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 to small to large number).
To compute this flux, we use an quadrature formula with one point, the middle point of the edge. Consider a triangle
T with three vertices (a,b,c). Let denote the vertices numbers by ia,ib,ic, and define the three edge vectors e0,e1,e2
by sgn(ib -ic)(b -c), sgn(ic -ia)(c -a), sgn(ia -ib)(a -b),
The three basis functions are:
 | (12.3) |
where |T|is the area of the triangle T.
So we have N = 2, kPi = 6; npPi = 3; and:
- Pp =
- α0 = -e20,α1 = e10, α2 = -e21,α3 = e11, α4 = -e22,α5 = e12 (effectively, the vector (-e2m,e1m) is
orthogonal to the edge em = (e1m,e2m) with a length equal to the side of the edge or equal to ∫
em1).
- ik = {0,0,1,1,2,2},
- pk = {0,0,1,1,2,2}, jk = {0,1,0,1,0,1,0,1}.
12.2 Which class of add
Add file FE_ADD.cppin directory src/femlibfor example first to initialize :
#include "error.hpp"
#include "rgraph.hpp"
using namespace std;
#include "RNM.hpp"
#include "fem.hpp"
#include "FESpace.hpp"
#include "AddNewFE.h"
namespace Fem2D {
Second, you are just a class which derive for public TypeOfFElike:
class TypeOfFE_RTortho : public TypeOfFE { public:
static int Data[]; // some numbers
TypeOfFE_RTortho():
TypeOfFE( 0+3+0, // nb degree of freedom on element
2, // dimension N of vectorial FE (1 if scalar FE)
Data, // the array data
1, // nb of subdivision for plotting
1, // nb of sub finite element (generaly 1)
6, // number kPi of coef to build the interpolator (12.1)
3, // number npPi of integration point to build interpolator
0 // an array to store the coef αk to build interpolator
// here this array is no constant so we have
// to rebuilt for each element.
)
{
const R2 Pt[] = { R2(0.5,0.5), R2(0.0,0.5), R2(0.5,0.0) };
// the set of Point in
for (int p=0,kk=0;p<3;p++) {
P_Pi_h[p]=Pt[p];
for (int j=0;j<2;j++)
pij_alpha[kk++]= IPJ(p,p,j); }} // definition of ik,pk,jk in
(12.1)
void FB(const bool ⋆ watdd, const Mesh & Th,const Triangle & K,
const R2 &PHat, RNMK_ & val) const;
void Pi_h_alpha(const baseFElement & K,KN_<double> & v) const ;
} ;
where the array data is form with the concatenation of five array of size NbDoFand one array of size
N.
This array is:
int TypeOfFE_RTortho::Data[]={
// for each df 0,1,3 :
3,4,5, // the support of the node of the df
0,0,0, // the number of the df on the node
0,1,2, // the node of the df
0,0,0, // the df come from which FE (generally 0)
0,1,2, // which are de df on sub FE
0,0 }; // for each component j = 0,N - 1 it give the sub FE
associated
where the support is a number 0,1,2 for vertex support, 3,4,5 for edge support, and finaly 6 for element
support.
The function to defined the function ωiK, this function return the value of all the basics function or this derivatives in
array val, computed at point PHaton the reference triangle corresponding to point R2 P=K(Phat);on the
current triangle K.
The index i,j,k of the array val(i,j,k) corresponding to:
-
i
- is basic function number on finite element i
[0,NoF[
-
j
- is the value of component j
[0,N[
-
k
- is the type of computed value f(P),dx(f)(P),dy(f)(P),... i
[0,last_operatortype[. Remark for
optimization, this value is computed only if whatd[k] is true, and the numbering is defined with
enum operatortype { op_id=0,
op_dx=1,op_dy=2,
op_dxx=3,op_dyy=4,
op_dyx=5,op_dxy=5,
op_dz=6,
op_dzz=7,
op_dzx=8,op_dxz=8,
op_dzy=9,op_dyz=9
};
const int last_operatortype=10;
The shape function :
void TypeOfFE_RTortho::FB(const bool ⋆whatd,const Mesh & Th,const Triangle & K,
const R2 & PHat,RNMK_ & val) const
{ //
R2 P(K(PHat));
R2 A(K[0]), B(K[1]),C(K[2]);
R l0=1-P.x-P.y,l1=P.x,l2=P.y;
assert(val.N() >=3);
assert(val.M()==2 );
val=0;
R a=1./(2⋆K.area);
R a0= K.EdgeOrientation(0) ⋆ a ;
R a1= K.EdgeOrientation(1) ⋆ a ;
R a2= K.EdgeOrientation(2) ⋆ a ;
//
------------
if (whatd[op_id]) // value of the
function
{
assert(val.K()>op_id);
RN_ f0(val('.',0,0)); // value first
component
RN_ f1(val('.',1,0)); // value second
component
f1[0] = (P.x-A.x)⋆a0;
f0[0] = -(P.y-A.y)⋆a0;
f1[1] = (P.x-B.x)⋆a1;
f0[1] = -(P.y-B.y)⋆a1;
f1[2] = (P.x-C.x)⋆a2;
f0[2] = -(P.y-C.y)⋆a2;
}
//
----------------
if (whatd[op_dx]) // value of the dx of
function
{
assert(val.K()>op_dx);
val(0,1,op_dx) = a0;
val(1,1,op_dx) = a1;
val(2,1,op_dx) = a2;
}
if (whatd[op_dy])
{
assert(val.K()>op_dy);
val(0,0,op_dy) = -a0;
val(1,0,op_dy) = -a1;
val(2,0,op_dy) = -a2;
}
for (int i= op_dy; i< last_operatortype ; i++)
if (whatd[op_dx])
assert(op_dy);
}
The function to defined the coefficient αk:
void TypeOfFE_RT::Pi_h_alpha(const baseFElement & K,KN_<double> & v) const
{
const Triangle & T(K.T);
for (int i=0,k=0;i<3;i++)
{
R2 E(T.Edge(i));
R signe = T.EdgeOrientation(i) ;
v[k++]= signe⋆E.y;
v[k++]=-signe⋆E.x;
}
}
Now , we just need to add a new key work in FreeFem++, Two way, with static or dynamic link so at the end of the
file, we add :
With dynamic link is very simple (see section C of appendix), just add before the end of FEM2d namespaceadd:
static TypeOfFE_RTortho The_TypeOfFE_RTortho; //
static AddNewFE("RT0Ortho", The_TypeOfFE_RTortho);
} // FEM2d
namespace
Try with ”./load.link” command in examples++-load/and see BernardiRaugel.cppor Morley.cpp
new finite element examples.
Otherwise with static link (for expert only), add
// let the 2 globals
variables
static TypeOfFE_RTortho The_TypeOfFE_RTortho; //
// ----- the name in freefem
----
static ListOfTFE typefemRTOrtho("RT0Ortho", & The_TypeOfFE_RTortho); //
// link with FreeFem++ do not work with static library .a
// FH so add a extern name to call in init_static_FE
// (see end of FESpace.cpp)
void init_FE_ADD() { };
// --- end --
} // FEM2d
namespace
To inforce in loading of this new finite element, we have to add the two new lines close to the end of files
src/femlib/FESpace.cpplike:
// correct Problem of static library link with new make
file
void init_static_FE()
{ // list of other FE
file.o
extern void init_FE_P2h() ;
init_FE_P2h() ;
extern void init_FE_ADD() ; // new line
1
init_FE_ADD(); // new line
2
}
and now you have to change the makefile.
First, create a file FE_ADD.cppcontening all this code, like in file src/femlib/Element_P2h.cpp, after
modifier the Makefile.amby adding the name of your file to the variable EXTRA_DISTlike:
# Makefile using Automake + Autoconf
# ----------------------------------
# $Id: addfe.tex,v 1.7 2008/11/24 19:10:15 hecht Exp $
# This is not compiled as a separate library because its
# interconnections with other libraries have not been solved.
EXTRA_DIST=BamgFreeFem.cpp BamgFreeFem.hpp CGNL.hpp CheckPtr.cpp \
ConjuguedGradrientNL.cpp DOperator.hpp Drawing.cpp Element_P2h.cpp \
Element_P3.cpp Element_RT.cpp fem3.hpp fem.cpp fem.hpp FESpace.cpp \
FESpace.hpp FESpace-v0.cpp FQuadTree.cpp FQuadTree.hpp gibbs.cpp \
glutdraw.cpp gmres.hpp MatriceCreuse.hpp MatriceCreuse_tpl.hpp \
MeshPoint.hpp mortar.cpp mshptg.cpp QuadratureFormular.cpp \
QuadratureFormular.hpp RefCounter.hpp RNM.hpp RNM_opc.hpp RNM_op.hpp \
RNM_tpl.hpp FE_ADD.cpp
and do in the freefem++root directory
autoreconf
./reconfigure
make
For codewarrior compilation add the file in the project an remove the flag in panal PPC linker FreeFEm++ Setting
Dead-strip Static Initializition Code Flag.