📄 addfe.tex
字号:
\section{Add new finite element}\label{AddnewFE}\subsection{Some notation}\def\Fb#1{\boldsymbol{\omega}^{K}_{#1}}\def\fbi{\mathbf{\omega}^{K}_{ij}}For a function $\boldsymbol{f}$ taking value in $\R^{N},\,N=1,2,\cdots$, we define the finite element approximation $\Pi_h\boldsymbol{f}$ of $\boldsymbol{f}$. Let us denote the number of thedegrees of freedom of the finite element by $NbDoF$. Then the $i$-thbase $\boldsymbol{\omega}^{K}_{i}$ ($i=0,\cdots,NbDoF-1$) of thefinite element space has the $j$-th component$\mathbf{\omega}^{K}_{ij}$ for $j=0,\cdots,N-1$.The operator $\Pi_{h}$ is called the interpolator of the finite element.We have the identity $\boldsymbol{\omega}^{K}_{i} = \Pi_{h} \boldsymbol{\omega}^{K}_{i} $.Formally, the interpolator $\Pi_{h}$ is constructed by the following formula:\begin{equation}\label{eq-interpo}\Pi_{h} \boldsymbol{f} = \sum_{k=0}^{\mathtt{kPi}-1} \alpha_k \boldsymbol{f}_{j_{k}}(P_{p_{k}}) \boldsymbol{\omega}^{K}_{i_{k}}\end{equation}where $P_{p}$ is a set of $npPi$ points,%\begin{remark}In the formula (\ref{eq-interpo}), the list $ p_{k},\, j_{k},\, i_{k}$ depend just on the type of finite element (not on the element), but the coefficient $\alpha_{k}$ can be depending on the element.%\end{remark}\medskip%\begin{example} Example 1: classical scalar Lagrange finite element, first we have $\mathtt{kPi}=\mathtt{npPi}=\mathtt{NbOfNode}$ and\begin{itemize}\item $P_{p}$ is the point of the nodal points\item the $\alpha_k=1$, because we take the value of the function at the point $P_{k}$\item $p_{k}=k$ , $j_{k}=k$ because we have one node per function.\item $j_{k}=0$ because $N=1$\end{itemize}%\end{example}%\begin{example} Example 2: The Raviart-Thomas finite element:\begin{equation} RT0_{h} = \{ \mathbf{v} \in H(div) / \forall K \in \mathcal{T}_{h} \quad \mathbf{v}_{|K}(x,y) = \vecttwo{\alpha_{K}}{\beta_{K}} + \gamma_{K}\vecttwo{x}{y} \} \label{eq:RT0-fe}\end{equation} The degree of freedom are the flux throw an edge $e$ of the mesh, where the flux of the function $\mathbf{f} : \R^2 \longrightarrow \R^2 $ is $\int_{e} \mathbf{f}.n_{e}$, $n_{e}$ 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 $(\mathbf{a},\mathbf{b},\mathbf{c})$.Let denote the vertices numbers by $i_{a},i_{b},i_{c}$, and define the three edge vectors $\mathbf{e}^{0},\mathbf{e}^{1},\mathbf{e}^{2}$by $ sgn(i_{b}-i_{c})(\mathbf{b}-\mathbf{c})$, $sgn(i_{c}-i_{a})(\mathbf{c}-\mathbf{a})$, $sgn(i_{a}-i_{b})(\mathbf{a}-\mathbf{b})$, The three basis functions are:\begin{equation} \boldsymbol{\omega}^{K}_{0}= \frac{sgn(i_{b}-i_{c})}{2|T|}(x-a),\quad \boldsymbol{\omega}^{K}_{1}= \frac{sgn(i_{c}-i_{a})}{2|T|}(x-b),\quad \boldsymbol{\omega}^{K}_{2}= \frac{sgn(i_{a}-i_{b})}{2|T|}(x-c),\end{equation}where $|T|$ is the area of the triangle $T$.So we have $N=2$, $\mathtt{kPi}=6; \mathtt{npPi}=3;$ and:\begin{itemize}\item $P_{p} = \left\{\frac{\mathbf{b}+\mathbf{c}}{2},\frac{\mathbf{a}+\mathbf{c}}{2},\frac{\mathbf{b}+\mathbf{a}}{2} \right\}$\item $\alpha_{0}= - \mathbf{e}^{0}_{2}, \alpha_{1}= \mathbf{e}^{0}_{1}$, $\alpha_{2}= - \mathbf{e}^{1}_{2}, \alpha_{3}= \mathbf{e}^{1}_{1}$, $\alpha_{4}= - \mathbf{e}^{2}_{2}, \alpha_{5}= \mathbf{e}^{2}_{1}$ (effectively, the vector $ ( -\mathbf{e}^{m}_{2}, \mathbf{e}^{m}_{1}) $ is orthogonal to the edge $\mathbf{e}^{m}= (e^m_{1},e^m_{2})$ with a length equal to the side of the edge or equal to $\int_{e^m} 1$).\item $i_{k}=\{0,0,1,1,2,2\}$,\item $p_{k}=\{0,0,1,1,2,2\}$ , $j_{k}=\{0,1,0,1,0,1,0,1\}$.\end{itemize}%\end{example}\subsection{Which class of add}Add file \texttt{FE\_ADD.cpp} in directory \texttt{src/femlib} for examplefirst to initialize :\bFF#include "error.hpp"#include "rgraph.hpp"using namespace std;#include "RNM.hpp"#include "fem.hpp"#include "FESpace.hpp"#include "AddNewFE.h"namespace Fem2D {\eFFSecond, you are just a class which derive for \texttt{ public TypeOfFE} like:\bFF@class TypeOfFE_RTortho : public TypeOfFE { public: static int Data[]; // some numbers \hfilll TypeOfFE_RTortho(): TypeOfFE( 0+3+0, // nb degree of freedom on element \hfilll 2, // dimension $N$ of vectorial FE (1 if scalar FE)\hfilll Data, // the array data\hfilll 1, // nb of subdivision for plotting\hfilll 1, // nb of sub finite element (generaly 1)\hfilll 6, // number $kPi$ of coef to build the interpolator (\ref{eq-interpo})\hfilll 3, // number $npPi$ of integration point to build interpolator\hfilll 0 // an array to store the coef $\alpha_k$ to build interpolator \hfilll // here this array is no constant so we have \hfilll // to rebuilt for each element.\hfilll ) { const R2 Pt[] = { R2(0.5,0.5), R2(0.0,0.5), R2(0.5,0.0) }; // the set of Point in $\hat{K}$ 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 $i_{k},p_{k},j_{k}$ in (\ref{eq-interpo}) 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 ;} ;\eFFwhere the array data is form with the concatenation of five array of size \texttt{NbDoF} and onearray of size \texttt{N}.This array is:\bFF@int TypeOfFE_RTortho::Data[]={ // for each df 0,1,3 : \hfilll 3,4,5,// the support of the node of the df \hfilll 0,0,0,// the number of the df on the node \hfilll 0,1,2,// the node of the df \hfilll 0,0,0,// the df come from which FE (generally 0) \hfilll 0,1,2,// which are de df on sub FE \hfilll 0,0 };// for each component $j=0,N-1$ it give the sub FE associated\eFFwhere 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 $\boldsymbol{\omega}^{K}_{i}$, this function returnthe value of all the basics function or this derivatives in array\texttt{val}, computed at point \texttt{PHat} on the reference triangle correspondingto point \texttt{R2 P=K(Phat);} on the current triangle \texttt{K}.The index $i,j,k$ of the array $val(i,j,k)$ corresponding to:\begin{description}\item[$i$] is basic function number on finite element $i \in [0,NoF[ $\item[$j$] is the value of component $ j \in [0,N[ $\item[$k$] is the type of computed value $f(P),dx(f)(P), dy(f)(P), ...$$i \in [0,\mathtt{last\_operatortype}[ $. Remark for optimization, this value is computed only if $whatd[k]$ is true, and the numbering is defined with\bFF@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;\eFF\end{description}The shape function :\bFF 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);}\eFFThe function to defined the coefficient $\alpha_{k}$:\bFFvoid 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; }}\eFFNow , we just need to add a new key work in \texttt{FreeFem++},Two way, with static or dynamic link soat the end of the file, we add :\medskipWith dynamic link is very simple (see section \ref{Dynamical link} of appendix), just addbefore the end of \texttt{FEM2d namespace}add: \bFFstatic TypeOfFE_RTortho The_TypeOfFE_RTortho; //static AddNewFE("RT0Ortho", The_TypeOfFE_RTortho); } // FEM2d namespace\eFFTry with "./load.link" command in \texttt{examples++-load/} andsee \texttt{BernardiRaugel.cpp} or \texttt{Morley.cpp} new finite element examples.\medskip {\bf Otherwise} with static link (for expert only), add\bFF// let the 2 globals variablesstatic 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 \hfilll// FH so add a extern name to call in \texttt{init\_static\_FE} \hfilll// (see end of FESpace.cpp) \hfilllvoid init_FE_ADD() { };// --- end -- \hfilll} // FEM2d namespace\eFFTo inforce in loading of this new finite element,we have to add the two new lines close to the end of files \texttt{src/femlib/FESpace.cpp}like:\bFF// correct Problem of static library link with new make filevoid 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}\eFFand now you have to change the makefile.First, create a file \texttt{FE\_ADD.cpp} contening all this code, like in file \texttt{src/femlib/Element\_P2h.cpp},after modifier the \texttt{Makefile.am} by adding the name of your fileto the variable \texttt{EXTRA\_DIST} like:\begin{verbatim}# 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\end{verbatim}and do in the \texttt{freefem++} root directory\begin{verbatim} autoreconf ./reconfigure make\end{verbatim} For codewarrior compilation add the file in the project an remove the flagin panal PPC linker FreeFEm++ Setting Dead-strip Static Initializition Code Flag.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -