PolyDiM
C++ library for POLYtopal DIscretization Methods
Loading...
Searching...
No Matches
FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp
Go to the documentation of this file.
1// _LICENSE_HEADER_
2//
3// Copyright (C) 2019 - 2025.
4// Terms register on the GPL-3.0 license.
5//
6// This file can be redistributed and/or modified under the license terms.
7//
8// See top level LICENSE file for more details.
9//
10// This file can be used citing references in CITATION.cff file.
11
12#ifndef __FEM_Tetrahedron_PCC_3D_ReferenceElement_HPP
13#define __FEM_Tetrahedron_PCC_3D_ReferenceElement_HPP
14
15#include "Eigen/Eigen"
17#include "IOStream.hpp"
18#include "QuadratureData.hpp"
20
21namespace Polydim
22{
23namespace FEM
24{
25namespace PCC
26{
28{
29 unsigned int Dimension;
30 unsigned int Order;
31 unsigned int NumDofs0D;
32 unsigned int NumDofs1D;
33 unsigned int NumDofs2D;
34 unsigned int NumDofs3D;
35
36 std::map<std::pair<unsigned int, unsigned int>, std::pair<unsigned int, bool>> Edges_by_vertices;
37 std::map<std::pair<unsigned int, unsigned int>, unsigned int> Faces_by_edge_vertex;
38 std::map<std::pair<unsigned int, unsigned int>, std::pair<std::array<unsigned int, 2>, bool>> Faces_by_edges;
39
40 unsigned int NumBasisFunctions;
41 Eigen::MatrixXd DofPositions;
42 std::vector<std::array<unsigned int, 4>> DofTypes;
43
45
47 std::vector<Eigen::MatrixXd> ReferenceBasisFunctionDerivativeValues;
48
51};
52
54{
55 public:
57 {
59
60 result.Order = order;
61 result.Dimension = 3;
62
63 result.Edges_by_vertices = {{{0, 1}, {0, true}},
64 {{1, 0}, {0, false}},
65 {{1, 2}, {1, true}},
66 {{2, 1}, {1, false}},
67 {{2, 0}, {2, true}},
68 {{0, 2}, {2, false}},
69 {{0, 3}, {3, true}},
70 {{3, 0}, {3, false}},
71 {{1, 3}, {4, false}},
72 {{3, 1}, {4, true}},
73 {{2, 3}, {5, false}},
74 {{3, 2}, {5, true}}};
75
76 result.Faces_by_edge_vertex = {{{0, 2}, 0},
77 {{1, 0}, 0},
78 {{2, 1}, 0},
79 {{0, 3}, 1},
80 {{4, 0}, 1},
81 {{3, 1}, 1},
82 {{2, 3}, 2},
83 {{5, 0}, 2},
84 {{3, 2}, 2},
85 {{1, 3}, 3},
86 {{5, 1}, 3},
87 {{4, 2}, 3}};
88
89 result.Faces_by_edges = {{{0, 1}, {std::array<unsigned int, 2>({0, 0}), true}},
90 {{1, 2}, {std::array<unsigned int, 2>({0, 1}), true}},
91 {{2, 0}, {std::array<unsigned int, 2>({0, 2}), true}},
92 {{1, 0}, {std::array<unsigned int, 2>({0, 2}), false}},
93 {{2, 1}, {std::array<unsigned int, 2>({0, 0}), false}},
94 {{0, 2}, {std::array<unsigned int, 2>({0, 1}), false}},
95 {{0, 4}, {std::array<unsigned int, 2>({1, 0}), true}},
96 {{4, 3}, {std::array<unsigned int, 2>({1, 1}), true}},
97 {{3, 0}, {std::array<unsigned int, 2>({1, 2}), true}},
98 {{4, 0}, {std::array<unsigned int, 2>({1, 2}), false}},
99 {{3, 4}, {std::array<unsigned int, 2>({1, 0}), false}},
100 {{0, 3}, {std::array<unsigned int, 2>({1, 1}), false}},
101 {{2, 5}, {std::array<unsigned int, 2>({2, 0}), true}},
102 {{5, 3}, {std::array<unsigned int, 2>({2, 1}), true}},
103 {{3, 2}, {std::array<unsigned int, 2>({2, 2}), true}},
104 {{5, 2}, {std::array<unsigned int, 2>({2, 2}), false}},
105 {{3, 5}, {std::array<unsigned int, 2>({2, 0}), false}},
106 {{2, 3}, {std::array<unsigned int, 2>({2, 1}), false}},
107 {{1, 5}, {std::array<unsigned int, 2>({3, 0}), true}},
108 {{5, 4}, {std::array<unsigned int, 2>({3, 1}), true}},
109 {{4, 1}, {std::array<unsigned int, 2>({3, 2}), true}},
110 {{5, 1}, {std::array<unsigned int, 2>({3, 2}), false}},
111 {{4, 5}, {std::array<unsigned int, 2>({3, 0}), false}},
112 {{1, 4}, {std::array<unsigned int, 2>({3, 1}), false}}};
113
114 if (order == 0)
115 {
116 result.NumDofs0D = 0;
117 result.NumDofs1D = 0;
118 result.NumDofs2D = 0;
119 result.NumDofs3D = 1;
120 result.NumBasisFunctions = 1;
121 result.DofPositions.setZero(3, result.NumBasisFunctions);
122 result.DofPositions.col(0) << 1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0;
123
125 result.BoundaryReferenceElement_Data = boundary_reference_element.Create(order);
126
129
133
134 return result;
135 }
136
137 result.NumDofs0D = 1;
138 result.NumDofs1D = order - 1;
139 result.NumDofs2D = order > 2 ? (order - 2) * (order - 1) / 2 : 0;
140 result.NumDofs3D = order > 3 ? (order - 3) * (order - 2) * (order - 1) / 6 : 0;
141 result.NumBasisFunctions = 4 * result.NumDofs0D + 6 * result.NumDofs1D + 4 * result.NumDofs2D + result.NumDofs3D;
142
143 result.DofTypes.resize(result.NumBasisFunctions);
144 result.DofPositions.resize(result.Dimension, result.NumBasisFunctions);
145 result.DofPositions.col(0) << 0.0, 0.0, 0.0;
146 result.DofPositions.col(1) << 1.0, 0.0, 0.0;
147 result.DofPositions.col(2) << 0.0, 1.0, 0.0;
148 result.DofPositions.col(3) << 0.0, 0.0, 1.0;
149
150 result.DofTypes[0] = {order, 0, 0, 0};
151 result.DofTypes[1] = {0, order, 0, 0};
152 result.DofTypes[2] = {0, 0, order, 0};
153 result.DofTypes[3] = {0, 0, 0, order};
154
155 if (order > 1)
156 {
157 unsigned int dof = 4;
158
159 // edge x
160 for (unsigned int d = 0; d < result.NumDofs1D; d++)
161 {
162 result.DofPositions.col(dof) << (d + 1.0) / ((double)order), 0.0, 0.0;
163 result.DofTypes[dof] = {order - 1 - d, d + 1, 0, 0};
164 dof++;
165 }
166
167 // edge x - y
168 for (unsigned int d = 0; d < result.NumDofs1D; d++)
169 {
170 result.DofPositions.col(dof) << (result.NumDofs1D - d) / ((double)order), (d + 1.0) / ((double)order), 0.0;
171 result.DofTypes[dof] = {0, order - d - 1, d + 1, 0};
172 dof++;
173 }
174
175 // edge y
176 for (unsigned int d = 0; d < result.NumDofs1D; d++)
177 {
178 result.DofPositions.col(dof) << 0.0, (result.NumDofs1D - d) / ((double)order), 0.0;
179 result.DofTypes[dof] = {d + 1, 0, order - d - 1, 0};
180 dof++;
181 }
182
183 // edge z
184 for (unsigned int d = 0; d < result.NumDofs1D; d++)
185 {
186 result.DofPositions.col(dof) << 0.0, 0.0, (d + 1.0) / ((double)order);
187 result.DofTypes[dof] = {order - d - 1, 0, 0, d + 1};
188 dof++;
189 }
190
191 // edge x - z
192 for (unsigned int d = 0; d < result.NumDofs1D; d++)
193 {
194 result.DofPositions.col(dof) << (d + 1.0) / ((double)order), 0.0, (result.NumDofs1D - d) / ((double)order);
195 result.DofTypes[dof] = {0, d + 1, 0, order - d - 1};
196 dof++;
197 }
198
199 // edge y - z
200 for (unsigned int d = 0; d < result.NumDofs1D; d++)
201 {
202 result.DofPositions.col(dof) << 0.0, (d + 1.0) / ((double)order), (result.NumDofs1D - d) / ((double)order);
203 result.DofTypes[dof] = {0, 0, d + 1, order - d - 1};
204 dof++;
205 }
206
207 if (order > 2)
208 {
209 // face x - y
210 for (unsigned int d1 = 0; d1 < result.NumDofs1D - 1; d1++) // x
211 {
212 for (unsigned int d2 = 0; d2 < result.NumDofs1D - 1 - d1; d2++) // y
213 {
214 result.DofPositions.col(dof) << (d1 + 1.0) / ((double)order), (d2 + 1.0) / ((double)order), 0.0;
215 result.DofTypes[dof] = {order - d1 - d2 - 2, d1 + 1, d2 + 1, 0};
216 dof++;
217 }
218 }
219
220 // face x - z
221 for (unsigned int d1 = 0; d1 < result.NumDofs1D - 1; d1++) // x
222 {
223 for (unsigned int d2 = 0; d2 < result.NumDofs1D - 1 - d1; d2++) // z
224 {
225 result.DofPositions.col(dof) << (d1 + 1.0) / ((double)order), 0.0, (d2 + 1.0) / ((double)order);
226 result.DofTypes[dof] = {order - d1 - d2 - 2, d1 + 1, 0, d2 + 1};
227 dof++;
228 }
229 }
230
231 // face y - z
232 for (unsigned int d1 = 0; d1 < result.NumDofs1D - 1; d1++) // y
233 {
234 for (unsigned int d2 = 0; d2 < result.NumDofs1D - 1 - d1; d2++) // z
235 {
236 result.DofPositions.col(dof) << 0.0, (d1 + 1.0) / ((double)order), (d2 + 1.0) / ((double)order);
237 result.DofTypes[dof] = {order - d1 - d2 - 2, 0, d1 + 1, d2 + 1};
238 dof++;
239 }
240 }
241
242 // face x - y - z
243 for (unsigned int d1 = 0; d1 < result.NumDofs1D - 1; d1++) // x
244 {
245 for (unsigned int d2 = 0; d2 < result.NumDofs1D - 1 - d1; d2++) // y
246 {
247 result.DofPositions.col(dof) << (d1 + 1.0) / ((double)order), (d2 + 1.0) / ((double)order),
248 1.0 - (d1 + 1.0) / ((double)order) - (d2 + 1.0) / ((double)order);
249 result.DofTypes[dof] = {0, d1 + 1, d2 + 1, order - d1 - d2 - 2};
250 dof++;
251 }
252 }
253
254 if (order > 3)
255 {
256 // internal
257 for (unsigned int d3 = 0; d3 < result.NumDofs1D - 2; d3++)
258 {
259 for (unsigned int d1 = 0; d1 < result.NumDofs1D - 2 - d3; d1++) // x
260 {
261 for (unsigned int d2 = 0; d2 < result.NumDofs1D - 2 - d1 - d3; d2++) // y
262 {
263 result.DofPositions.col(dof) << (d1 + 1.0) / ((double)order),
264 (d2 + 1.0) / ((double)order), (d3 + 1.0) / ((double)order);
265
266 result.DofTypes[dof] = {order - d1 - d2 - d3 - 3, d1 + 1, d2 + 1, d3 + 1};
267 dof++;
268 }
269 }
270 }
271 }
272 }
273 }
274
277
279 result.BoundaryReferenceElement_Data = boundary_reference_element.Create(order);
280
283
287
288 return result;
289 }
290 // ***************************************************************************
291 Eigen::MatrixXd EvaluateLambda(const Eigen::MatrixXd &points) const
292 {
293 Eigen::MatrixXd lambda;
294 lambda.setZero(points.cols(), 4);
295
296 lambda.col(0) = 1.0 - points.row(0).array() - points.row(1).array() - points.row(2).array();
297 lambda.col(1) = points.row(0);
298 lambda.col(2) = points.row(1);
299 lambda.col(3) = points.row(2);
300
301 return lambda;
302 }
303 // ***************************************************************************
304 std::vector<Eigen::MatrixXd> EvaluateGradLambda(const Eigen::MatrixXd &points) const
305 {
306 std::vector<Eigen::MatrixXd> gradLambda(3);
307
308 gradLambda[0].setZero(points.cols(), 4);
309 gradLambda[1].setZero(points.cols(), 4);
310 gradLambda[2].setZero(points.cols(), 4);
311
312 gradLambda[0].col(0).setConstant(-1.0);
313 gradLambda[1].col(0).setConstant(-1.0);
314 gradLambda[2].col(0).setConstant(-1.0);
315
316 gradLambda[0].col(1).setOnes();
317 gradLambda[1].col(1).setZero();
318 gradLambda[2].col(1).setZero();
319
320 gradLambda[0].col(2).setZero();
321 gradLambda[1].col(2).setOnes();
322 gradLambda[2].col(2).setZero();
323
324 gradLambda[0].col(3).setZero();
325 gradLambda[1].col(3).setZero();
326 gradLambda[2].col(3).setOnes();
327
328 return gradLambda;
329 }
330 // ***************************************************************************
331 Eigen::MatrixXd EvaluateBasisFunctions(const Eigen::MatrixXd &points,
332 const Polydim::FEM::PCC::FEM_Tetrahedron_PCC_3D_ReferenceElement_Data &reference_element_data) const
333 {
334 const Eigen::MatrixXd lambda_functions = EvaluateLambda(points);
335 const unsigned int order = reference_element_data.Order;
336 if (order == 1)
337 return lambda_functions;
338
339 Eigen::MatrixXd basis_functions_values = Eigen::MatrixXd::Ones(points.cols(), reference_element_data.NumBasisFunctions);
340 Eigen::VectorXd normalized_factor = Eigen::VectorXd::Ones(reference_element_data.NumBasisFunctions);
341
342 const Eigen::MatrixXd dofs_lambda_functions = EvaluateLambda(reference_element_data.DofPositions);
343
344 for (unsigned int dof = 0; dof < reference_element_data.NumBasisFunctions; dof++)
345 {
346 for (unsigned int i = 0; i < 4; i++)
347 {
348 for (unsigned int p = 0; p < reference_element_data.DofTypes[dof][i]; p++)
349 {
350 normalized_factor(dof) = normalized_factor(dof) * (dofs_lambda_functions(dof, i) - p / ((double)order));
351 basis_functions_values.col(dof) =
352 basis_functions_values.col(dof).array() * (lambda_functions.col(i).array() - p / ((double)order));
353 }
354 }
355
356 basis_functions_values.col(dof) /= normalized_factor(dof);
357 }
358
359 return basis_functions_values;
360 }
361 // ***************************************************************************
362 std::vector<Eigen::MatrixXd> EvaluateBasisFunctionDerivatives(
363 const Eigen::MatrixXd &points,
364 const Polydim::FEM::PCC::FEM_Tetrahedron_PCC_3D_ReferenceElement_Data &reference_element_data) const
365 {
366
367 const std::vector<Eigen::MatrixXd> grad_lambda = EvaluateGradLambda(points);
368 const unsigned int order = reference_element_data.Order;
369 if (order == 1)
370 return grad_lambda;
371
372 std::vector<Eigen::MatrixXd> values(reference_element_data.Dimension,
373 Eigen::MatrixXd::Zero(points.cols(), reference_element_data.NumBasisFunctions));
374
375 const auto basis_function_values = EvaluateBasisFunctions(points, reference_element_data);
376 const Eigen::MatrixXd lambda_functions = EvaluateLambda(points);
377
378 for (unsigned int d = 0; d < reference_element_data.Dimension; d++)
379 {
380 for (unsigned int dof = 0; dof < reference_element_data.NumBasisFunctions; dof++)
381 {
382 for (unsigned int i = 0; i < 4; i++)
383 {
384 for (unsigned int p = 0; p < reference_element_data.DofTypes[dof][i]; p++)
385 {
386 values[d].col(dof) = values[d].col(dof).array() +
387 grad_lambda[d].col(i).array() * basis_function_values.col(dof).array() /
388 (lambda_functions.col(i).array() - p / ((double)order));
389 }
390 }
391 }
392 }
393
394 return values;
395 }
396};
397} // namespace PCC
398} // namespace FEM
399} // namespace Polydim
400
401#endif
static QuadratureData FillPointsAndWeights(const unsigned int &order)
Referement: https://people.math.sc.edu/Burkardt/m_src/tetrahedron_arbq_rule/tetrahedron_arbq_rule....
Definition Quadrature_Gauss3D_Tetrahedron_PositiveWeights.cpp:21
Factory that builds the reference element data for a 1D PCC finite element.
Definition FEM_PCC_1D_ReferenceElement.hpp:67
Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement_Data Create(const unsigned int order, const Polydim::FEM::PCC::FEM_PCC_1D_Types type=Polydim::FEM::PCC::FEM_PCC_1D_Types::Equispaced, const unsigned int quadrature_order=0) const
Definition FEM_PCC_1D_ReferenceElement.hpp:69
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:54
Eigen::MatrixXd EvaluateBasisFunctions(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_Tetrahedron_PCC_3D_ReferenceElement_Data &reference_element_data) const
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:331
Polydim::FEM::PCC::FEM_Tetrahedron_PCC_3D_ReferenceElement_Data Create(const unsigned int order) const
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:56
Eigen::MatrixXd EvaluateLambda(const Eigen::MatrixXd &points) const
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:291
std::vector< Eigen::MatrixXd > EvaluateBasisFunctionDerivatives(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_Tetrahedron_PCC_3D_ReferenceElement_Data &reference_element_data) const
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:362
std::vector< Eigen::MatrixXd > EvaluateGradLambda(const Eigen::MatrixXd &points) const
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:304
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:52
FEM_Triangle_PCC_2D_ReferenceElement_Data Create(const unsigned int order) const
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:54
Definition FEM_MCC_2D_LocalSpace.cpp:17
Definition QuadratureData.hpp:22
Eigen::MatrixXd Points
Definition QuadratureData.hpp:23
Reference element data for a 1D PCC finite element.
Definition FEM_PCC_1D_ReferenceElement.hpp:46
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:28
Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data BoundaryReferenceElement_Data
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:50
Gedim::Quadrature::QuadratureData ReferenceTetrahedronQuadrature
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:44
unsigned int NumDofs1D
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:32
std::vector< Eigen::MatrixXd > ReferenceBasisFunctionDerivativeValues
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:47
unsigned int NumBasisFunctions
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:40
unsigned int NumDofs2D
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:33
std::vector< std::array< unsigned int, 4 > > DofTypes
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:42
std::map< std::pair< unsigned int, unsigned int >, unsigned int > Faces_by_edge_vertex
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:37
Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement_Data EdgeReferenceElement_Data
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:49
std::map< std::pair< unsigned int, unsigned int >, std::pair< unsigned int, bool > > Edges_by_vertices
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:36
Eigen::MatrixXd DofPositions
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:41
std::map< std::pair< unsigned int, unsigned int >, std::pair< std::array< unsigned int, 2 >, bool > > Faces_by_edges
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:38
unsigned int Order
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:30
Eigen::MatrixXd ReferenceBasisFunctionValues
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:46
unsigned int NumDofs0D
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:31
unsigned int NumDofs3D
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:34
unsigned int Dimension
Definition FEM_Tetrahedron_PCC_3D_ReferenceElement.hpp:29
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:28