LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
Loading...
Searching...
No Matches
lin_fe.cc
1/* **************************************************************************
2 * LehrFEM++ - A simple C++ finite element libray for teaching
3 * Developed from 2018 at the Seminar of Applied Mathematics of ETH Zurich,
4 * lead developers Dr. R. Casagrande and Prof. R. Hiptmair
5 ***************************************************************************/
6
16#include "lin_fe.h"
17
18#include <Eigen/Eigen>
19
20namespace lf::uscalfe {
21std::shared_ptr<spdlog::logger> &LinearFELaplaceElementMatrix::Logger() {
22 static auto logger =
23 base::InitLogger("lf::uscalfe::LinearFELaplaceElementMatrix::Logger");
24 return logger;
25}
26
28 const Eigen::Vector2d &xh) {
29 // clang-format off
30 return (Eigen::Matrix<double, 4, 2>(4, 2) <<
31 xh[1] - 1, xh[0] - 1,
32 1 - xh[1], -xh[0] ,
33 xh[1] , xh[0] ,
34 -xh[1] , 1 - xh[0]
35 ).finished();
36 // clang-format on
37}
38
40 const lf::mesh::Entity &cell) const {
41 // Topological type of the cell
42 const lf::base::RefEl ref_el{cell.RefEl()};
43
44 // Obtain the vertex coordinates of the cell, which completely
45 // describe its shape.
46 const lf::geometry::Geometry *geo_ptr = cell.Geometry();
47 LF_ASSERT_MSG(geo_ptr != nullptr, "Invalid geometry!");
48 LF_ASSERT_MSG((geo_ptr->DimGlobal() == 2) && (geo_ptr->DimLocal() == 2),
49 "Only 2D implementation available!");
50 // Matrix storing corner coordinates in its columns
51 auto vertices = geo_ptr->Global(ref_el.NodeCoords());
52 // Debugging output
53 SPDLOG_LOGGER_TRACE(Logger(), "{}, shape={}", ref_el, vertices);
54
55 // 4x4 dense matrix for returning result
56 ElemMat elem_mat = ElemMat::Zero(4, 4);
57
58 // Computations differ depending on the type of the cell
59 switch (ref_el) {
61 // Triangular cell: straight edges assumed, which means that the triangle
62 // is an affine image of the unit triangle and that the gradients of the
63 // local shape functions (= barycentric coordinate functions) are
64 // constant.
65 LF_ASSERT_MSG((vertices.cols() == 3) && (vertices.rows() == 2),
66 "Wrong size of vertex matrix!");
67 // Set up an auxiliary 3x3-matrix with a leading column 1 and
68 // the vertex coordinates in its right 3x2 block
69 Eigen::Matrix<double, 3, 3> X; // temporary matrix
70 X.block<3, 1>(0, 0) = Eigen::Vector3d::Ones();
71 X.block<3, 2>(0, 1) = vertices.transpose();
72 // The determinant of the auxliriary matrix also supplies the area
73 const double area = 0.5 * std::abs(X.determinant());
74 SPDLOG_LOGGER_TRACE(Logger(), "Area: {} <-> {}", area,
75 0.5 * geo_ptr->IntegrationElement(kTriabc));
76
77 // Compute the gradients of the barycentric coordinate functions
78 // and store them in the columns of a 2x3 matrix grad_bary_coords
79 Eigen::Matrix<double, 2, 3> grad_bary_coords{
80 X.inverse().block<2, 3>(1, 0)};
81 // Since the gradients are constant local integration is easy
82 elem_mat.block<3, 3>(0, 0) =
83 area * grad_bary_coords.transpose() * grad_bary_coords;
84 break;
85 }
87 LF_ASSERT_MSG((vertices.cols() == 4) && (vertices.rows() == 2),
88 "Wrong size of vertex matrix!");
89 // Coefficient matrix for bilinear mapping to actual cell
90 // clang-format off
91 Eigen::Matrix<double, 2, 4> G(vertices *
92 (Eigen::Matrix<double, 4, 4>() <<
93 1, -1, -1, 1,
94 0, 1 , 0, -1,
95 0, 0, 0, 1,
96 0, 0, 1, -1)
97 .finished());
98 // clang-format on
99 // Coefficients for the determinant as a linear function in
100 // the reference coordinates
101 // clang-format off
102 Eigen::Vector3d detc{
103 (Eigen::Vector3d() <<
104 G(0, 1) * G(1, 2) - G(1, 1) * G(0, 2),
105 G(0, 1) * G(1, 3) - G(1, 1) * G(0, 3),
106 G(1, 2) * G(0, 3) - G(0, 2) * G(1, 3))
107 .finished()};
108 // clang-format on
109 // Determinant at a point in the reference element
110 auto detDPhi = [&detc](const Eigen::Vector2d &xh) -> double {
111 return std::abs(detc[0] + detc[1] * xh[0] + detc[2] * xh[1]);
112 };
113 SPDLOG_LOGGER_DEBUG(Logger(), "Determinant: {} <-> {}", detDPhi(kQuadpt),
114 geo_ptr->IntegrationElement(kQuadpt));
115
116 // Transposed adjunct matrix of Jacobian of transformation
117 auto DPhiadj =
118 [&G](const Eigen::Vector2d &xh) -> Eigen::Matrix<double, 2, 2> {
119 // clang-format off
120 return ((Eigen::Matrix<double, 2, 2>() <<
121 G(1, 2) + G(1, 3) * xh[0] , -G(1, 1) - G(1, 3) * xh[1],
122 -G(0, 2) - G(0, 3) * xh[0], G(0, 1) + G(0, 3) * xh[1])
123 .finished());
124 // clang-format on
125 };
126 // Output for debugging
127 SPDLOG_LOGGER_TRACE(Logger(), "InverseTransposedJacobian:\n{} <-> {}",
128 (DPhiadj(kQuadpt) / detDPhi(kQuadpt)),
129 (geo_ptr->JacobianInverseGramian(kQuadpt)));
130
131 // For a quadrilateral we have to use numerical quadrature based on
132 // a 2-2 tensor-product Gauss rule.
133 // Sum over quadrature points (weight= 0.5)
134 for (int q = 0; q < 4; ++q) {
135 // Obtain reference coordinates of current quadrature point
136 const Eigen::Vector2d qp(kQuadPoints[q]);
137 // Gradients of shape functions in quadrature points stored in
138 // the columns of a matrix
139 Eigen::Matrix<double, 2, 4> gradmat(DPhiadj(qp) *
140 DervRefShapFncts(qp).transpose());
141 // Update of element matrix by contribution from current quadrature
142 // point, whose entries are dot products of gradients
143 elem_mat += gradmat.transpose() * gradmat / detDPhi(qp);
144 }
145 // Scaling with quadrature weights
146 elem_mat *= 0.25;
147 break;
148 }
149 default: {
150 LF_ASSERT_MSG(false, "Illegal cell type");
151 }
152 } // end switch
153
154 auto nv = vertices.cols();
155 SPDLOG_LOGGER_TRACE(Logger(), "Element matrix\n{}",
156 elem_mat.block(0, 0, nv, nv));
157 SPDLOG_LOGGER_TRACE(Logger(), "Row sums = {},\ncol sums = {}",
158 elem_mat.block(0, 0, nv, nv).colwise().sum(),
159 elem_mat.block(0, 0, nv, nv).rowwise().sum().transpose());
160
161 // Return the element matrix
162 return elem_mat;
163}
164
165// No implementation for TEMPLATE LinearFELocalLoadVector here
166
167std::shared_ptr<spdlog::logger> &LinearFeLocalLoadVectorLogger() {
168 static auto logger =
169 base::InitLogger("lf::uscalfe::LinearFeLocalLoadVectorLogger");
170 return logger;
171}
172
173} // namespace lf::uscalfe
Represents a reference element with all its properties.
Definition ref_el.h:109
static constexpr RefEl kTria()
Returns the reference triangle.
Definition ref_el.h:161
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
Definition ref_el.h:169
Interface class for shape information on a mesh cell in the spirit of parametric finite element metho...
virtual Eigen::MatrixXd Global(const Eigen::MatrixXd &local) const =0
Map a number of points in local coordinates into the global coordinate system.
virtual dim_t DimLocal() const =0
Dimension of the domain of this mapping.
virtual dim_t DimGlobal() const =0
Dimension of the image of this mapping.
virtual Eigen::MatrixXd JacobianInverseGramian(const Eigen::MatrixXd &local) const =0
Evaluate the Jacobian * Inverse Gramian ( ) simultaneously at numPoints.
virtual Eigen::VectorXd IntegrationElement(const Eigen::MatrixXd &local) const =0
The integration element (factor appearing in integral transformation formula, see below) at number of...
Interface class representing a topological entity in a cellular complex
Definition entity.h:42
virtual const geometry::Geometry * Geometry() const =0
Describes the geometry of this entity.
virtual base::RefEl RefEl() const =0
Describes the reference element type of this entity.
Eigen::Matrix< double, 4, 4 > ElemMat
Definition lin_fe.h:49
const Eigen::Matrix< double, 2, 1 > kTriabc
Definition lin_fe.h:83
const Eigen::Matrix< double, 2, 1 > kQuadpt
Definition lin_fe.h:86
ElemMat Eval(const lf::mesh::Entity &cell) const
main routine for the computation of element matrices
Definition lin_fe.cc:39
static std::shared_ptr< spdlog::logger > & Logger()
Used by LinearFELaplaceElementMatrix to log additional (debug) info.
Definition lin_fe.cc:21
static Eigen::Matrix< double, 4, 2 > DervRefShapFncts(const Eigen::Vector2d &xh)
Definition lin_fe.cc:27
const std::array< Eigen::Vector2d, 4 > kQuadPoints
Definition lin_fe.h:76
std::shared_ptr< spdlog::logger > InitLogger(const std::string &name)
Create a spdlog logger, register it in the spdlog registry and initialize it with LehrFEM++ specific ...
Collects data structures and algorithms designed for scalar finite element methods primarily meant fo...
std::shared_ptr< spdlog::logger > & LinearFeLocalLoadVectorLogger()
Used by LinearFELocalLoadVector to log additional (debug) information during vector assembly.
Definition lin_fe.cc:167