PolyDiM
C++ library for POLYtopal DIscretization Methods
Loading...
Searching...
No Matches
FEM_Hexahedron_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_Hexahedron_PCC_3D_ReferenceElement_HPP
13#define __FEM_Hexahedron_PCC_3D_ReferenceElement_HPP
14
15#include "Eigen/Eigen"
17#include "QuadratureData.hpp"
19
20namespace Polydim
21{
22namespace FEM
23{
24namespace PCC
25{
27{
28 unsigned int Dimension;
29 unsigned int Order;
30 unsigned int NumDofs0D;
31 unsigned int NumDofs1D;
32 unsigned int NumDofs2D;
33 unsigned int NumDofs3D;
34
35 std::map<std::pair<unsigned int, unsigned int>, std::pair<unsigned int, bool>> Edges_by_vertices;
36 std::map<std::pair<unsigned int, unsigned int>, unsigned int> Faces_by_edges;
37
38 unsigned int NumBasisFunctions;
39 Eigen::MatrixXd DofPositions;
40 std::vector<std::array<unsigned int, 3>> DofTypes;
41
43
45 std::vector<Eigen::MatrixXd> ReferenceBasisFunctionDerivativeValues;
46
49};
50
52{
53 public:
54 Eigen::MatrixXd Vertices;
55
57 {
58 Vertices = Eigen::MatrixXd::Zero(3, 8);
59 Vertices << 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0,
60 1.0, 1.0, 1.0, 1.0;
61 }
62
64
66 {
67 if (order <= 0)
68 throw std::runtime_error("not valid order");
69
71
72 result.Order = order;
73 result.Dimension = 3;
74 result.NumBasisFunctions = (order + 1) * (order + 1) * (order + 1);
75 result.NumDofs0D = 1;
76 result.NumDofs1D = order - 1;
77 result.NumDofs2D = (order - 1) * (order - 1);
78 result.NumDofs3D = (order - 1) * (order - 1) * (order - 1);
79
80 // Edge directions
81 result.Edges_by_vertices = {
82 {{0, 1}, {0, true}}, {{1, 0}, {0, false}}, {{1, 2}, {1, true}}, {{2, 1}, {1, false}},
83 {{2, 3}, {2, false}}, {{3, 2}, {2, true}}, {{3, 0}, {3, false}}, {{0, 3}, {3, true}},
84 {{4, 5}, {4, true}}, {{5, 4}, {4, false}}, {{5, 6}, {5, true}}, {{6, 5}, {5, false}},
85 {{6, 7}, {6, false}}, {{7, 6}, {6, true}}, {{7, 4}, {7, false}}, {{4, 7}, {7, true}},
86 {{0, 4}, {8, true}}, {{4, 0}, {8, false}}, {{1, 5}, {9, true}}, {{5, 1}, {9, false}},
87 {{3, 7}, {10, true}}, {{7, 3}, {10, false}}, {{2, 6}, {11, true}}, {{6, 2}, {11, false}}};
88
89 result.Faces_by_edges = {{{0, 2}, 0}, {{2, 0}, 0}, {{1, 3}, 0}, {{3, 1}, 0}, {{4, 6}, 1}, {{6, 4}, 1},
90 {{5, 7}, 1}, {{7, 5}, 1}, {{0, 4}, 2}, {{4, 0}, 2}, {{8, 9}, 2}, {{9, 8}, 2},
91 {{2, 6}, 3}, {{6, 2}, 3}, {{10, 11}, 3}, {{11, 10}, 3}, {{7, 3}, 4}, {{3, 7}, 4},
92 {{8, 10}, 4}, {{10, 8}, 4}, {{1, 5}, 5}, {{9, 11}, 5}, {{11, 9}, 5}, {{5, 1}, 5}};
93
96 const Eigen::VectorXd reference_edge_dofs_poisitions = result.EdgeReferenceElement_Data.DofPositions.row(0);
97
98 // Reordering Dofs using convention [point, edge, cell]
99 result.DofPositions.setZero(3, result.NumBasisFunctions);
100 result.DofTypes.resize(result.NumBasisFunctions);
101
102 for (unsigned int d3 = 0; d3 < 2; d3++)
103 {
104 for (unsigned int d1 = 0; d1 < 2; d1++)
105 {
106 if (d1 == 0)
107 {
108 for (unsigned int d2 = 0; d2 < 2; d2++)
109 {
110 result.DofPositions.col(4 * d3 + 2 * d1 + d2) << reference_edge_dofs_poisitions(d2),
111 reference_edge_dofs_poisitions(d1), reference_edge_dofs_poisitions(d3);
112 result.DofTypes[4 * d3 + 2 * d1 + d2] = {d2, d1, d3};
113 }
114 }
115 else
116 {
117 for (unsigned int d2 = 0; d2 < 2; d2++)
118 {
119 const unsigned int index = (d2 == 0) ? 1 : 0;
120 result.DofPositions.col(4 * d3 + 2 * d1 + d2) << reference_edge_dofs_poisitions(index),
121 reference_edge_dofs_poisitions(d1), reference_edge_dofs_poisitions(d3);
122 result.DofTypes[4 * d3 + 2 * d1 + d2] = {index, d1, d3};
123 }
124 }
125 }
126 }
127
128 if (order > 1)
129 {
130 for (unsigned int d3 = 0; d3 < 2; d3++)
131 {
132 for (unsigned int d1 = 0; d1 < 2; d1++)
133 {
134 result.DofPositions.row(0).segment(8 * result.NumDofs0D + (2 * d1 + 4 * d3) * result.NumDofs1D,
135 result.NumDofs1D) =
136 reference_edge_dofs_poisitions.segment(2, result.NumDofs1D);
137 result.DofPositions.row(1).segment(8 * result.NumDofs0D + (2 * d1 + 4 * d3) * result.NumDofs1D,
138 result.NumDofs1D) =
139 Eigen::VectorXd::Ones(result.NumDofs1D) * reference_edge_dofs_poisitions(d1);
140 result.DofPositions.row(2).segment(8 * result.NumDofs0D + (2 * d1 + 4 * d3) * result.NumDofs1D,
141 result.NumDofs1D) =
142 Eigen::VectorXd::Ones(result.NumDofs1D) * reference_edge_dofs_poisitions(d3);
143
144 for (unsigned int d2 = 2; d2 < result.EdgeReferenceElement_Data.NumBasisFunctions; d2++)
145 result.DofTypes[8 * result.NumDofs0D + (2 * d1 + 4 * d3) * result.NumDofs1D + d2 - 2] = {d2, d1, d3};
146 }
147 }
148
149 for (unsigned int d3 = 0; d3 < 2; d3++)
150 {
151 for (unsigned int d1 = 0; d1 < 2; d1++)
152 {
153 const unsigned index = (d1 == 1) ? 0 : 1;
154 result.DofPositions.row(0).segment(8 * result.NumDofs0D + (2 * d1 + 1 + 4 * d3) * result.NumDofs1D,
155 result.NumDofs1D) =
156 Eigen::VectorXd::Ones(result.NumDofs1D) * reference_edge_dofs_poisitions(index);
157 result.DofPositions.row(1).segment(8 * result.NumDofs0D + (2 * d1 + 1 + 4 * d3) * result.NumDofs1D,
158 result.NumDofs1D) =
159 reference_edge_dofs_poisitions.segment(2, result.NumDofs1D);
160 result.DofPositions.row(2).segment(8 * result.NumDofs0D + (2 * d1 + 1 + 4 * d3) * result.NumDofs1D,
161 result.NumDofs1D) =
162 Eigen::VectorXd::Ones(result.NumDofs1D) * reference_edge_dofs_poisitions(d3);
163
164 for (unsigned int d2 = 2; d2 < result.EdgeReferenceElement_Data.NumBasisFunctions; d2++)
165 result.DofTypes[8 * result.NumDofs0D + (2 * d1 + 1 + 4 * d3) * result.NumDofs1D + d2 - 2] = {index, d2, d3};
166 }
167 }
168
169 // Verticel edges:
170 for (unsigned int d3 = 0; d3 < 2; d3++) // y
171 {
172 for (unsigned int d1 = 0; d1 < 2; d1++) // x
173 {
174 result.DofPositions.row(0).segment(8 * result.NumDofs0D + (8 + d1 + 2 * d3) * result.NumDofs1D,
175 result.NumDofs1D) =
176 Eigen::VectorXd::Ones(result.NumDofs1D) * reference_edge_dofs_poisitions(d1);
177 result.DofPositions.row(1).segment(8 * result.NumDofs0D + (8 + d1 + 2 * d3) * result.NumDofs1D,
178 result.NumDofs1D) =
179 Eigen::VectorXd::Ones(result.NumDofs1D) * reference_edge_dofs_poisitions(d3);
180 result.DofPositions.row(2).segment(8 * result.NumDofs0D + (8 + d1 + 2 * d3) * result.NumDofs1D,
181 result.NumDofs1D) =
182 reference_edge_dofs_poisitions.segment(2, result.NumDofs1D);
183
184 for (unsigned int d2 = 2; d2 < result.EdgeReferenceElement_Data.NumBasisFunctions; d2++) // z
185 result.DofTypes[8 * result.NumDofs0D + (8 + d1 + 2 * d3) * result.NumDofs1D + d2 - 2] = {d1, d3, d2};
186 }
187 }
188
189 unsigned int dof = 8 * result.NumDofs0D + 12 * result.NumDofs1D;
190
191 // Face dofs
192 for (unsigned int d3 = 0; d3 < 2; d3++) // z
193 {
194 for (unsigned int d1 = 2; d1 < result.EdgeReferenceElement_Data.NumBasisFunctions; d1++) // x
195 {
196 for (unsigned int d2 = 2; d2 < result.EdgeReferenceElement_Data.NumBasisFunctions; d2++) // y
197 {
198 result.DofPositions.col(dof) << reference_edge_dofs_poisitions(d1),
199 reference_edge_dofs_poisitions(d2), reference_edge_dofs_poisitions(d3);
200 result.DofTypes[dof] = {d1, d2, d3};
201 dof++;
202 }
203 }
204 }
205
206 for (unsigned int d3 = 0; d3 < 2; d3++) // y
207 {
208 for (unsigned int d1 = 2; d1 < result.EdgeReferenceElement_Data.NumBasisFunctions; d1++) // x
209 {
210 for (unsigned int d2 = 2; d2 < result.EdgeReferenceElement_Data.NumBasisFunctions; d2++) // z
211 {
212 result.DofPositions.col(dof) << reference_edge_dofs_poisitions(d1),
213 reference_edge_dofs_poisitions(d3), reference_edge_dofs_poisitions(d2);
214 result.DofTypes[dof] = {d1, d3, d2};
215 dof++;
216 }
217 }
218 }
219
220 for (unsigned int d3 = 0; d3 < 2; d3++) // x
221 {
222 for (unsigned int d1 = 2; d1 < result.EdgeReferenceElement_Data.NumBasisFunctions; d1++) // y
223 {
224 for (unsigned int d2 = 2; d2 < result.EdgeReferenceElement_Data.NumBasisFunctions; d2++) // z
225 {
226 result.DofPositions.col(dof) << reference_edge_dofs_poisitions(d3),
227 reference_edge_dofs_poisitions(d1), reference_edge_dofs_poisitions(d2);
228 result.DofTypes[dof] = {d3, d1, d2};
229 dof++;
230 }
231 }
232 }
233
234 // Interni
235 for (unsigned int d3 = 2; d3 < result.EdgeReferenceElement_Data.NumBasisFunctions; d3++) // x
236 {
237 for (unsigned int d1 = 2; d1 < result.EdgeReferenceElement_Data.NumBasisFunctions; d1++) // y
238 {
239 for (unsigned int d2 = 2; d2 < result.EdgeReferenceElement_Data.NumBasisFunctions; d2++) // z
240 {
241 result.DofPositions.col(dof) << reference_edge_dofs_poisitions(d3),
242 reference_edge_dofs_poisitions(d1), reference_edge_dofs_poisitions(d2);
243 result.DofTypes[dof] = {d3, d1, d2};
244 dof++;
245 }
246 }
247 }
248 }
249
251 result.BoundaryReferenceElement_Data = boundary_reference_element.Create(order);
252
255
259
260 return result;
261 }
262 // ***************************************************************************
263 Eigen::MatrixXd EvaluateBasisFunctions(const Eigen::MatrixXd &points,
264 const Polydim::FEM::PCC::FEM_Hexahedron_PCC_3D_ReferenceElement_Data &reference_element_data) const
265 {
266
267 const unsigned int num_points = points.cols();
268 Eigen::MatrixXd x = Eigen::MatrixXd::Zero(3, num_points);
269 x.row(0) = points.row(0);
270 Eigen::MatrixXd y = Eigen::MatrixXd::Zero(3, num_points);
271 y.row(0) = points.row(1);
272 Eigen::MatrixXd z = Eigen::MatrixXd::Zero(3, num_points);
273 z.row(0) = points.row(2);
274
275 Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement boundary_reference_element;
276 const Eigen::MatrixXd values_x =
277 boundary_reference_element.EvaluateBasisFunctions(x, reference_element_data.EdgeReferenceElement_Data);
278 const Eigen::MatrixXd values_y =
279 boundary_reference_element.EvaluateBasisFunctions(y, reference_element_data.EdgeReferenceElement_Data);
280 const Eigen::MatrixXd values_z =
281 boundary_reference_element.EvaluateBasisFunctions(z, reference_element_data.EdgeReferenceElement_Data);
282
283 Eigen::MatrixXd values = Eigen::MatrixXd::Ones(num_points, reference_element_data.NumBasisFunctions);
284
285 for (unsigned int d = 0; d < reference_element_data.NumBasisFunctions; d++)
286 {
287 const auto &dofType = reference_element_data.DofTypes[d];
288 values.col(d) =
289 values_x.col(dofType[0]).array() * values_y.col(dofType[1]).array() * values_z.col(dofType[2]).array();
290 }
291
292 return values;
293 }
294 // ***************************************************************************
295 std::vector<Eigen::MatrixXd> EvaluateBasisFunctionDerivatives(const Eigen::MatrixXd &points,
296 const Polydim::FEM::PCC::FEM_Hexahedron_PCC_3D_ReferenceElement_Data &reference_element_data) const
297 {
298 const unsigned int num_points = points.cols();
299 Eigen::MatrixXd x = Eigen::MatrixXd::Zero(3, num_points);
300 x.row(0) = points.row(0);
301 Eigen::MatrixXd y = Eigen::MatrixXd::Zero(3, num_points);
302 y.row(0) = points.row(1);
303 Eigen::MatrixXd z = Eigen::MatrixXd::Zero(3, num_points);
304 z.row(0) = points.row(2);
305
306 Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement boundary_reference_element;
307 const Eigen::MatrixXd values_x =
308 boundary_reference_element.EvaluateBasisFunctions(x, reference_element_data.EdgeReferenceElement_Data);
309 const Eigen::MatrixXd values_y =
310 boundary_reference_element.EvaluateBasisFunctions(y, reference_element_data.EdgeReferenceElement_Data);
311 const Eigen::MatrixXd values_z =
312 boundary_reference_element.EvaluateBasisFunctions(z, reference_element_data.EdgeReferenceElement_Data);
313
314 const std::vector<Eigen::MatrixXd> values_x_dx =
315 boundary_reference_element.EvaluateBasisFunctionDerivatives(x, reference_element_data.EdgeReferenceElement_Data);
316 const std::vector<Eigen::MatrixXd> values_y_dy =
317 boundary_reference_element.EvaluateBasisFunctionDerivatives(y, reference_element_data.EdgeReferenceElement_Data);
318 const std::vector<Eigen::MatrixXd> values_z_dz =
319 boundary_reference_element.EvaluateBasisFunctionDerivatives(z, reference_element_data.EdgeReferenceElement_Data);
320
321 std::vector<Eigen::MatrixXd> grad_values(3, Eigen::MatrixXd::Ones(num_points, reference_element_data.NumBasisFunctions));
322
323 for (unsigned int d = 0; d < reference_element_data.NumBasisFunctions; d++)
324 {
325 const auto &dofType = reference_element_data.DofTypes[d];
326 grad_values[0].col(d) = values_x_dx[0].col(dofType[0]).array() * values_y.col(dofType[1]).array() *
327 values_z.col(dofType[2]).array();
328 grad_values[1].col(d) = values_x.col(dofType[0]).array() * values_y_dy[0].col(dofType[1]).array() *
329 values_z.col(dofType[2]).array();
330 grad_values[2].col(d) = values_x.col(dofType[0]).array() * values_y.col(dofType[1]).array() *
331 values_z_dz[0].col(dofType[2]).array();
332 }
333
334 return grad_values;
335 }
336 // ***************************************************************************
337 std::array<Eigen::MatrixXd, 9> EvaluateBasisFunctionSecondDerivatives(const Eigen::MatrixXd &,
339 {
340 throw std::runtime_error("not implemented method");
341 }
342};
343} // namespace PCC
344} // namespace FEM
345} // namespace Polydim
346
347#endif
static QuadratureData FillPointsAndWeights(const unsigned int &order)
Definition Quadrature_Gauss3D_Hexahedron.cpp:18
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
Eigen::MatrixXd EvaluateBasisFunctions(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement_Data &reference_element_data) const
Definition FEM_PCC_1D_ReferenceElement.hpp:199
std::vector< Eigen::MatrixXd > EvaluateBasisFunctionDerivatives(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement_Data &reference_element_data) const
Definition FEM_PCC_1D_ReferenceElement.hpp:207
Definition FEM_MCC_2D_LocalSpace.cpp:17
Definition QuadratureData.hpp:22
Eigen::MatrixXd Points
Definition QuadratureData.hpp:23
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:27
Eigen::MatrixXd ReferenceBasisFunctionValues
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:44
std::vector< Eigen::MatrixXd > ReferenceBasisFunctionDerivativeValues
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:45
unsigned int NumBasisFunctions
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:38
unsigned int NumDofs3D
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:33
Gedim::Quadrature::QuadratureData ReferenceHexahedronQuadrature
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:42
Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement_Data EdgeReferenceElement_Data
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:47
std::vector< std::array< unsigned int, 3 > > DofTypes
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:40
unsigned int Dimension
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:28
std::map< std::pair< unsigned int, unsigned int >, std::pair< unsigned int, bool > > Edges_by_vertices
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:35
unsigned int NumDofs1D
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:31
std::map< std::pair< unsigned int, unsigned int >, unsigned int > Faces_by_edges
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:36
Polydim::FEM::PCC::FEM_Quadrilateral_PCC_2D_ReferenceElement_Data BoundaryReferenceElement_Data
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:48
Eigen::MatrixXd DofPositions
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:39
unsigned int NumDofs0D
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:30
unsigned int NumDofs2D
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:32
unsigned int Order
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:29
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:52
Polydim::FEM::PCC::FEM_Hexahedron_PCC_3D_ReferenceElement_Data Create(const unsigned int order) const
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:65
std::array< Eigen::MatrixXd, 9 > EvaluateBasisFunctionSecondDerivatives(const Eigen::MatrixXd &, const Polydim::FEM::PCC::FEM_Quadrilateral_PCC_2D_ReferenceElement_Data &) const
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:337
Eigen::MatrixXd Vertices
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:54
Eigen::MatrixXd EvaluateBasisFunctions(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_Hexahedron_PCC_3D_ReferenceElement_Data &reference_element_data) const
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:263
~FEM_Hexahedron_PCC_3D_ReferenceElement()
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:63
std::vector< Eigen::MatrixXd > EvaluateBasisFunctionDerivatives(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_Hexahedron_PCC_3D_ReferenceElement_Data &reference_element_data) const
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:295
FEM_Hexahedron_PCC_3D_ReferenceElement()
Definition FEM_Hexahedron_PCC_3D_ReferenceElement.hpp:56
Reference element data for a 1D PCC finite element.
Definition FEM_PCC_1D_ReferenceElement.hpp:46
Eigen::MatrixXd DofPositions
Definition FEM_PCC_1D_ReferenceElement.hpp:53
unsigned int NumBasisFunctions
Definition FEM_PCC_1D_ReferenceElement.hpp:52
Definition FEM_Quadrilateral_PCC_2D_ReferenceElement.hpp:28
Definition FEM_Quadrilateral_PCC_2D_ReferenceElement.hpp:52
Polydim::FEM::PCC::FEM_Quadrilateral_PCC_2D_ReferenceElement_Data Create(const unsigned int order) const
Definition FEM_Quadrilateral_PCC_2D_ReferenceElement.hpp:63