This article is devoted to the own implementation (Solker Joker FEM ) of the finite element method for systems of diffusion-reaction equations.
It is usually preferable to use ready-made solutions, but if there are specific features in the task, then the task is easier to solve using a simple library.
The finite element method [1-4] is a group of effective methods for solving problems of mathematical physics, continuum mechanics. FEM programming issues are devoted to sources [5β9].
Robinβs boundary problem for the system diffusion-reaction equations in a bounded domain with border :
Here , - vector of external normal to .
Multiply each of equations for an arbitrary test function , we integrate the obtained identities by , apply the Green formula and take into account the boundary conditions. Will get
We introduce the Sobolev functional space . Functions are called a weak solution of the original boundary value problem if the indicated identities are satisfied for an arbitrary test function .
Weak wording can be written as follows: find functions such that
Where - bilinear forms, - linear form:
We introduce in space finite-dimensional subspace . According to the Galerkin method, we arrive at a discrete problem: find functions such that
Let be - basis . If we put , , then the task is reduced to SLAE with respect to unknown :
or
The simplest example of a subspace - the space of continuous piecewise linear functions. Region is divided into finite elements (usually triangles), and on each triangle the functions of are linear. In the FEM, the basic functions are chosen so that in most parts of the domain they vanish, then there will be many zeros in the SLAE matrix. As basic functions take "pyramids", which are equal to 1 in one grid node and 0 in the other nodes. Each node of the grid has its own basic function, and the dimension subspace is equal to the number of nodes in the grid.
Note that if th and nodes are not connected by an edge, then , so when summing over it is enough to go through only the indices for which between m and nodes are edge either .
Thus, the solution of the boundary value problem by the finite element method is reduced to the construction and solution of the corresponding SLAE.
To set the function , you need to specify its values ββin the grid nodes. We denote the coordinates -th node through and the value of the function at node - through .
To find the value of a function at an arbitrary point belonging to the triangle with th th and vertices, we introduce the barycentric coordinates that take values ββfrom 0 to 1 and are related to Cartesian coordinates the following relations (see [3, Section 4.7.1], [4, p. 35]):
From here
Where - area of ββa triangle with a sign.
The value of the function can be found by the formula .
Let us reduce the integral over the boundary edge with m and ends of the integral over a segment :
Here - edge length, ,
.
To calculate the last integral, apply the Gauss quadrature formula:
Points and weight factors taken from the table [3, sec. 5.9.2].
We will reduce the integral of the triangle with th th and vertices of a triangle integral :
Here - area of ββa triangle, ,
.
To calculate the last integral, we apply the quadrature formula [3, Sec. 5.11].
Testing is difficult in this subject domain [10], so it is important that the code be written very clearly. OOP allows you to increase the readability of the code; to use OOP, you need to select a set of concepts and formulate an algorithm in these terms. This makes it possible in the first place to pay attention to the algorithm, and only then to the implementation details.
To build the grid, the FreeFem ++ package is used, the triangulation is saved in the .mesh format.
The library introduces the Mesh
class, which contains mesh information that is read from the file.
To write the algorithm, classes of basic functions and integrands of functions (products of functions) are introduced, which are inherited from the base classes Integrand
and BoundaryIntegrand
. In these classes there are support
(carrier) and boundary_support
(boundary carrier) fields, respectively. The carrier is a list of triangles on which the function is not equal to 0. The boundary carrier is a list of boundary edges on which the function is not equal to 0. Also, the Value
method is defined for classes of integrand functions, which calculates the value of the function at a given point.
The Integrate
and BoundaryIntegrate
functions take as input an integrand function, iterate through the carrier list and call the integration function along a given triangle (or boundary edge), which is defined in the Integrand
base class ( BoundaryIntegrand
) and calls the virtual function Value
.
Thus, the SLAU build code has a simple form:
for (int i = 0; i < data.N; ++i) { for (int j = 0; j < data.mesh.nodes_num; ++j) { for (auto s : data.mesh.adjacent_nodes[j]) { sys.AddCoeff(i, j, i, s, data.a[i] * Integrate(grad(phi[s]) * grad(phi[j])) + BoundaryIntegrate(data.b[i] * phi[s] * phi[j]) ); } for (int k = 0; k < data.N; ++k) { for (auto s : data.mesh.adjacent_nodes[j]) { sys.AddCoeff(i, j, k, s, Integrate(data.q[i][k] * phi[s] * phi[j]) ); } } sys.AddRhs(i, j, Integrate(data.g[i] * phi[j]) + BoundaryIntegrate(data.b[i] * data.w[i] * phi[j]) ); } }
To solve the SLAE, an iterative method is used, implemented in the MTL4 library.
To find the solution value at a given point, it is necessary in a short time to find the triangle containing the given point. For this you can use a hash table.
Divide the region enclosing rectangle. on blocks where , , - the length and width of the enclosing rectangle, - the average size of the enclosing triangles of triangles triangles.
For each of blocks fill the list of triangles that intersect it. For this, let's iterate through all the triangles and find their enclosing rectangles,
for which it is easy to find the blocks crossing them.
When executing a query for a given point, we find the block to which it belongs, and we look at the list of triangles corresponding to this block, checking which of them the given point belongs to.
Testing the program was carried out on tasks with a known exact solution. With double grinding of the grid, the error decreases by about 4 times or 2 times, which indicates that the method has the 2nd or 1st order of accuracy. The reduction in the order of convergence to the 1st may be due to the inconsistency of the boundary conditions at the joints of the parts of the boundary on which different values ββof the function are given. .
The advantage of the developed library over large solvers is its simplicity, as well as the ability to take into account the specific features of the problem (piecewise constant coefficient in the boundary condition). In the future, we plan to implement a similar library for 3-dimensional tasks, which will be used to solve optimal control problems for the boundary coefficient in the complex heat exchange model, where this coefficient is piecewise constant [11].
Source: https://habr.com/ru/post/344564/