LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
Loading...
Searching...
No Matches
quad_o2.cc
1
9#include "quad_o2.h"
10
11#include <Eigen/Eigen>
12
13#include "point.h"
14#include "segment_o2.h"
15#include "tria_o2.h"
16
17namespace lf::geometry {
18
19QuadO2::QuadO2(Eigen::Matrix<double, Eigen::Dynamic, 8> coords)
20 : coords_(std::move(coords)),
21 alpha_(coords_.rows()),
22 beta_(coords_.rows(), 2),
23 gamma_(coords_.rows(), 2),
24 delta_(coords_.rows()),
25 epsilon_(coords_.rows(), 2),
26 gamma_x_2_(coords_.rows(), 2),
27 epsilon_x_2_(coords_.rows(), 2) {
28 /*
29 * 3 - 6 - 2 D - G - C
30 * | | | |
31 * 7 5 -> H F
32 * | | | |
33 * 0 - 4 - 1 A - E - B
34 */
35 const Eigen::VectorXd& A = coords_.col(0);
36 const Eigen::VectorXd& B = coords_.col(1);
37 const Eigen::VectorXd& C = coords_.col(2);
38 const Eigen::VectorXd& D = coords_.col(3);
39 const Eigen::VectorXd& E = coords_.col(4);
40 const Eigen::VectorXd& F = coords_.col(5);
41 const Eigen::VectorXd& G = coords_.col(6);
42 const Eigen::VectorXd& H = coords_.col(7);
43
44 alpha_ << A;
45 beta_ << -3. * A - B + 4. * E, -3. * A - D + 4. * H;
46 gamma_ << 2. * (A + B) - 4. * E, 2. * (A + D) - 4. * H;
47 delta_ << 5. * A - B - 3. * C - D - 4. * (E - F - G + H);
48 epsilon_ << -2. * (A + B - C - D) + 4. * (E - G),
49 -2. * (A - B - C + D) - 4. * (F - H);
50
51 // coefficients for Jacobian()
52 gamma_x_2_ << 2. * gamma_;
53 epsilon_x_2_ << 2. * epsilon_;
54}
55
56Eigen::MatrixXd QuadO2::Global(const Eigen::MatrixXd& local) const {
57 LF_VERIFY_MSG((0. <= local.array()).all() && (local.array() <= 1.).all(),
58 "local coordinates out of bounds for reference element");
59
60 auto local_squared = local.array().square();
61 return ((beta_ * local) + (gamma_ * local_squared.matrix()) +
62 (delta_ * local.row(0).cwiseProduct(local.row(1))) +
63 (epsilon_ *
64 (local_squared * local.colwise().reverse().array()).matrix()))
65 .colwise() +
66 alpha_;
67}
68
69Eigen::MatrixXd QuadO2::Jacobian(const Eigen::MatrixXd& local) const {
70 LF_VERIFY_MSG((0. <= local.array()).all() && (local.array() <= 1.).all(),
71 "local coordinates out of bounds for reference element");
72
73 auto local_squared_reversed = local.array().square().colwise().reverse();
74 auto local_colwise_product = local.row(0).cwiseProduct(local.row(1));
75
76 Eigen::MatrixXd tmp_epsilon(gamma_.rows(), 2 * local.cols());
77 Eigen::MatrixXd tmp_epsilon_x_2 = epsilon_x_2_.replicate(1, local.cols());
78 Eigen::MatrixXd tmp_gamma(gamma_.rows(), 2 * local.cols());
79
80 for (long i = 0; i < local.cols(); ++i) {
81 tmp_epsilon.block(0, 2 * i, tmp_epsilon.rows(), 2) =
82 epsilon_.rowwise().reverse().array().rowwise() *
83 local_squared_reversed.col(i).transpose().array();
84 tmp_epsilon_x_2.block(0, 2 * i, tmp_epsilon_x_2.rows(), 2) *=
85 local_colwise_product(i);
86 tmp_gamma.block(0, 2 * i, tmp_gamma.rows(), 2) =
87 gamma_x_2_.array().rowwise() * local.col(i).transpose().array();
88 }
89
90 Eigen::MatrixXd local_reversed = local.colwise().reverse();
91 local_reversed.resize(1, local.size());
92
93 return beta_.replicate(1, local.cols()) + tmp_gamma + tmp_epsilon +
94 tmp_epsilon_x_2 +
95 (local_reversed.replicate(delta_.rows(), 1).array().colwise() *
96 delta_.array())
97 .matrix();
98}
99
101 const Eigen::MatrixXd& local) const {
102 LF_VERIFY_MSG((0. <= local.array()).all() && (local.array() <= 1.).all(),
103 "local coordinates out of bounds for reference element");
104
105 Eigen::MatrixXd jac = Jacobian(local);
106 Eigen::MatrixXd jacInvGram(jac.rows(), jac.cols());
107
108 if (DimGlobal() == 2) {
109 for (long i = 0; i < local.cols(); ++i) {
110 auto jacobian = jac.block(0, 2 * i, 2, 2);
111 jacInvGram.block(0, 2 * i, 2, 2) << jacobian(1, 1), -jacobian(1, 0),
112 -jacobian(0, 1), jacobian(0, 0);
113 jacInvGram.block(0, 2 * i, 2, 2) /= jacobian.determinant();
114 }
115 } else {
116 for (long i = 0; i < local.cols(); ++i) {
117 auto jacobian = jac.block(0, 2 * i, jac.rows(), 2);
118
119 auto A = jacobian.col(0);
120 auto B = jacobian.col(1);
121 auto AB = A.dot(B);
122
123 Eigen::MatrixXd tmp(2, 2);
124 tmp << B.dot(B), -AB, -AB, A.dot(A);
125
126 jacInvGram.block(0, 2 * i, jac.rows(), 2) =
127 jacobian * tmp / tmp.determinant();
128 }
129 }
130
131 return jacInvGram;
132}
133
134Eigen::VectorXd QuadO2::IntegrationElement(const Eigen::MatrixXd& local) const {
135 LF_VERIFY_MSG((0. <= local.array()).all() && (local.array() <= 1.).all(),
136 "local coordinates out of bounds for reference element");
137
138 Eigen::MatrixXd jac = Jacobian(local);
139 Eigen::VectorXd intElem(local.cols());
140
141 if (DimGlobal() == 2) {
142 for (long i = 0; i < local.cols(); ++i) {
143 intElem(i) = std::abs(jac.block(0, 2 * i, 2, 2).determinant());
144 }
145 } else {
146 for (long i = 0; i < local.cols(); ++i) {
147 auto jacobian = jac.block(0, 2 * i, jac.rows(), 2);
148
149 auto A = jacobian.col(0);
150 auto B = jacobian.col(1);
151 auto AB = A.dot(B);
152
153 intElem(i) = std::sqrt(std::abs(A.dot(A) * B.dot(B) - AB * AB));
154 }
155 }
156
157 return intElem;
158}
159
160std::unique_ptr<Geometry> QuadO2::SubGeometry(dim_t codim, dim_t i) const {
161 switch (codim) {
162 case 0: {
163 LF_ASSERT_MSG(i == 0, "i is out of bounds");
164 return std::make_unique<QuadO2>(coords_);
165 }
166 case 1: {
167 LF_ASSERT_MSG(0 <= i && i <= 3, "i is out of bounds");
168 return std::make_unique<SegmentO2>(
169 (Eigen::Matrix<double, Eigen::Dynamic, 3>(DimGlobal(), 3)
170 << coords_.col(i),
171 coords_.col((i + 1) % 4), coords_.col(i + 4))
172 .finished());
173 }
174 case 2: {
175 LF_ASSERT_MSG(0 <= i && i <= 8, "i is out of bounds");
176 return std::make_unique<Point>(coords_.col(i));
177 }
178 default: {
179 LF_VERIFY_MSG(false, "codim is out of bounds")
180 }
181 }
182}
183
184std::vector<std::unique_ptr<Geometry>> QuadO2::ChildGeometry(
185 const RefinementPattern& ref_pat, lf::base::dim_t codim) const {
186 LF_VERIFY_MSG(ref_pat.RefEl() == lf::base::RefEl::kQuad(),
187 "Refinement pattern for " << ref_pat.RefEl().ToString());
188 LF_VERIFY_MSG(codim < 3, "Illegal codim " << codim);
189
190 const double hLattice = 1. / static_cast<double>(ref_pat.LatticeConst());
191 std::vector<std::unique_ptr<Geometry>> childGeoPtrs = {};
192
193 // get coordinates of childGeometries
194 std::vector<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>> childPolygons(
195 ref_pat.ChildPolygons(codim));
196
197 const base::size_type noChildren = childPolygons.size();
198 LF_VERIFY_MSG(
199 noChildren == ref_pat.NumChildren(codim),
200 "NumChildren " << noChildren << " <-> " << ref_pat.NumChildren(codim));
201
202 // create a geometry object for each child
203 for (size_t child = 0; child < noChildren; ++child) {
204 // codim == 0: a child triangle/quadrilateral is described by a lattice
205 // polygon with six/eight vertices
206 // codim == 1: a child segment is described by a polygon with three vertices
207 // codim == 2: a child point by a single point ("polygon with one corner")
208 LF_VERIFY_MSG(
209 childPolygons[child].rows() == 2,
210 "childPolygons[child].rows() = " << childPolygons[child].rows());
211 LF_VERIFY_MSG(
212 (childPolygons[child].cols() == (3 - codim)) ||
213 (childPolygons[child].cols() == 4),
214 "childPolygons[child].cols() = " << childPolygons[child].cols());
215
216 const Eigen::MatrixXd locChildPolygonCoords(
217 hLattice * childPolygons[child].cast<double>());
218
219 switch (codim) {
220 case 0: {
221 if (childPolygons[child].cols() == 3) {
222 Eigen::MatrixXd locChildCoords(locChildPolygonCoords.rows(), 6);
223 locChildCoords << locChildPolygonCoords,
224 (locChildPolygonCoords.col(0) + locChildPolygonCoords.col(1)) /
225 2.,
226 (locChildPolygonCoords.col(1) + locChildPolygonCoords.col(2)) /
227 2.,
228 (locChildPolygonCoords.col(2) + locChildPolygonCoords.col(0)) /
229 2.;
230
231 childGeoPtrs.push_back(
232 std::make_unique<TriaO2>(Global(locChildCoords)));
233
234 } else if (childPolygons[child].cols() == 4) {
235 Eigen::MatrixXd locChildCoords(locChildPolygonCoords.rows(), 8);
236 locChildCoords << locChildPolygonCoords,
237 (locChildPolygonCoords.col(0) + locChildPolygonCoords.col(1)) /
238 2.,
239 (locChildPolygonCoords.col(1) + locChildPolygonCoords.col(2)) /
240 2.,
241 (locChildPolygonCoords.col(2) + locChildPolygonCoords.col(3)) /
242 2.,
243 (locChildPolygonCoords.col(3) + locChildPolygonCoords.col(0)) /
244 2.;
245
246 childGeoPtrs.push_back(
247 std::make_unique<QuadO2>(Global(locChildCoords)));
248
249 } else {
250 LF_VERIFY_MSG(false, "childPolygons[" << child << "].cols() = "
251 << childPolygons[child].cols());
252 }
253
254 break;
255 }
256 case 1: {
257 Eigen::MatrixXd locChildCoords(locChildPolygonCoords.rows(), 3);
258 locChildCoords << locChildPolygonCoords,
259 (locChildPolygonCoords.col(0) + locChildPolygonCoords.col(1)) / 2.;
260
261 childGeoPtrs.push_back(
262 std::make_unique<SegmentO2>(Global(locChildCoords)));
263
264 break;
265 }
266 case 2: {
267 childGeoPtrs.push_back(
268 std::make_unique<Point>(Global(locChildPolygonCoords)));
269
270 break;
271 }
272 default: {
273 LF_VERIFY_MSG(false, "Illegal co-dimension");
274 }
275 }
276 }
277
278 return childGeoPtrs;
279}
280
281} // namespace lf::geometry
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
Definition ref_el.h:169
std::string ToString() const
Return a string representation of this Reference element.
Definition ref_el.h:458
base::RefEl::dim_t dim_t
Eigen::Matrix< double, Eigen::Dynamic, 2 > gamma_x_2_
Definition quad_o2.h:84
Eigen::MatrixXd Jacobian(const Eigen::MatrixXd &local) const override
Evaluate the jacobian of the mapping simultaneously at numPoints points.
Definition quad_o2.cc:69
Eigen::Matrix< double, Eigen::Dynamic, 2 > epsilon_x_2_
Definition quad_o2.h:85
Eigen::Matrix< double, Eigen::Dynamic, 2 > beta_
Definition quad_o2.h:78
Eigen::VectorXd IntegrationElement(const Eigen::MatrixXd &local) const override
The integration element (factor appearing in integral transformation formula, see below) at number of...
Definition quad_o2.cc:134
Eigen::Matrix< double, Eigen::Dynamic, 2 > gamma_
Definition quad_o2.h:79
Eigen::MatrixXd Global(const Eigen::MatrixXd &local) const override
Map a number of points in local coordinates into the global coordinate system.
Definition quad_o2.cc:56
Eigen::Matrix< double, Eigen::Dynamic, 8 > coords_
Coordinates of the 8 vertices/midpoints, stored in matrix columns.
Definition quad_o2.h:70
Eigen::MatrixXd JacobianInverseGramian(const Eigen::MatrixXd &local) const override
Evaluate the Jacobian * Inverse Gramian ( ) simultaneously at numPoints.
Definition quad_o2.cc:100
std::vector< std::unique_ptr< Geometry > > ChildGeometry(const RefinementPattern &ref_pat, lf::base::dim_t codim) const override
Generate geometry objects for child entities created in the course of refinement.
Definition quad_o2.cc:184
Eigen::Matrix< double, Eigen::Dynamic, 1 > alpha_
Definition quad_o2.h:77
Eigen::Matrix< double, Eigen::Dynamic, 1 > delta_
Definition quad_o2.h:80
Eigen::Matrix< double, Eigen::Dynamic, 2 > epsilon_
Definition quad_o2.h:81
QuadO2(Eigen::Matrix< double, Eigen::Dynamic, 8 > coords)
Constructor building quadrilateral from vertex/midpoint coordinates.
Definition quad_o2.cc:19
dim_t DimGlobal() const override
Dimension of the image of this mapping.
Definition quad_o2.h:39
std::unique_ptr< Geometry > SubGeometry(dim_t codim, dim_t i) const override
Construct a new Geometry() object that describes the geometry of the i-th sub-entity with codimension...
Definition quad_o2.cc:160
Abstract interface class for encoding topological local refinement
lf::base::size_type LatticeConst() const
Provides information about lattice constant used.
virtual lf::base::size_type NumChildren(lf::base::dim_t codim) const =0
provide number of child entities of a given co-dimension to be created by refinement
virtual std::vector< Eigen::Matrix< int, Eigen::Dynamic, Eigen::Dynamic > > ChildPolygons(lf::base::dim_t codim) const =0
provide lattice reference coordinates of vertices of child polygons
lf::base::RefEl RefEl() const
Returns topological type of entity for which the current object is set up.
unsigned int size_type
general type for variables related to size of arrays
Definition types.h:20
unsigned int dim_t
type for dimensions and co-dimensions and numbers derived from them
Definition types.h:32
Defines the Geometry interface and provides a number of classes that implement this interface + addit...
Definition compose.h:13