PolyDiM
C++ library for POLYtopal DIscretization Methods
Loading...
Searching...
No Matches
FEM_Triangle_PCC_2D_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_Triangle_PCC_2D_ReferenceElement_HPP
13#define __FEM_Triangle_PCC_2D_ReferenceElement_HPP
14
15#include "Eigen/Eigen"
17#include "QuadratureData.hpp"
19#include "VEM_PCC_Utilities.hpp"
20
21namespace Polydim
22{
23namespace FEM
24{
25namespace PCC
26{
50
52{
53 public:
54 FEM_Triangle_PCC_2D_ReferenceElement_Data Create(const unsigned int order) const
55 {
58
59 if (order == 0)
60 {
61 result.Dimension = 2;
62 result.Order = order;
63 result.NumDofs0D = 0;
64 result.NumDofs1D = 0;
65 result.NumDofs2D = 1;
66 result.NumBasisFunctions = 1;
67 result.DofTypes.setZero(3, result.NumBasisFunctions);
68 result.DofPositions.setZero(3, result.NumBasisFunctions);
69 result.DofPositions.col(0) << 1.0 / 3.0, 1.0 / 3.0, 0.0;
70
71 Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement boundary_reference_element;
73 boundary_reference_element.Create(order, Polydim::FEM::PCC::FEM_PCC_1D_Types::Equispaced);
74
76
82
83 return result;
84 }
85
86 result.Dimension = 2;
87 result.Order = order;
88 result.NumBasisFunctions = (order + 1) * (order + 2) / 2;
89
90 std::vector<unsigned int> nodeDofs = {0, order, result.NumBasisFunctions - 1};
91 std::list<unsigned int> cellDofs;
92 std::vector<std::list<unsigned int>> edgeDofs(3);
93
94 Eigen::MatrixXd localDofPositions = Eigen::MatrixXd::Zero(3, result.NumBasisFunctions);
95 Eigen::MatrixXi localDofTypes = Eigen::MatrixXi::Zero(3, result.NumBasisFunctions);
96
97 const double h = 1.0 / order;
98 unsigned int dof = 0;
99 for (unsigned int i = 0; i < order + 1; i++)
100 {
101 for (unsigned int j = 0; j < order + 1 - i; j++)
102 {
103 if (i == 0)
104 {
105 if (j > 0 && j < order - i)
106 edgeDofs[0].push_back(dof);
107 }
108 else if (i < order && (j == 0 || j == order - i))
109 {
110 if (j == 0)
111 edgeDofs[2].push_front(dof);
112 else
113 edgeDofs[1].push_back(dof);
114 }
115 else if (i < order)
116 cellDofs.push_back(dof);
117
118 localDofPositions.col(dof) << (double)j * h, (double)i * h, 0.0;
119 localDofTypes.col(dof) << order - i - j, j, i;
120
121 dof++;
122 }
123 }
124
125 // Reordering Dofs using convention [point, edge, cell]
126 result.NumDofs0D = nodeDofs.size() / 3;
127 result.NumDofs1D = edgeDofs[0].size();
128 result.NumDofs2D = cellDofs.size();
129 result.DofPositions.setZero(3, result.NumBasisFunctions);
130 result.DofTypes.setZero(3, result.NumBasisFunctions);
131
132 dof = 0;
133 for (const unsigned int dofIndex : nodeDofs)
134 {
135 result.DofPositions.col(dof) << localDofPositions.col(dofIndex);
136 result.DofTypes.col(dof) << localDofTypes.col(dofIndex);
137 dof++;
138 }
139 for (unsigned int e = 0; e < 3; e++)
140 {
141 for (const unsigned int dofIndex : edgeDofs.at(e))
142 {
143 result.DofPositions.col(dof) << localDofPositions.col(dofIndex);
144 result.DofTypes.col(dof) << localDofTypes.col(dofIndex);
145 dof++;
146 }
147 }
148 for (const unsigned int dofIndex : cellDofs)
149 {
150 result.DofPositions.col(dof) << localDofPositions.col(dofIndex);
151 result.DofTypes.col(dof) << localDofTypes.col(dofIndex);
152 dof++;
153 }
154
155 result.EdgeInternalPoints = Eigen::VectorXd::LinSpaced(result.NumDofs1D + 2, 0.0, 1.0).segment(1, result.NumDofs1D);
157
158 Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement boundary_reference_element;
160 boundary_reference_element.Create(order, Polydim::FEM::PCC::FEM_PCC_1D_Types::Equispaced);
161
163
169
170 return result;
171 }
172 // ***************************************************************************
173 Eigen::MatrixXd EvaluateBasisFunctions(const Eigen::MatrixXd &points,
174 const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data &reference_element_data) const
175 {
176 switch (reference_element_data.Order)
177 {
178 case 0:
179 return Eigen::VectorXd::Constant(points.cols(), 1.0);
180 default: {
181 const double h = 1.0 / reference_element_data.Order;
182 const Eigen::ArrayXd x = points.row(0).transpose();
183 const Eigen::ArrayXd y = points.row(1).transpose();
184 Eigen::MatrixXd values = Eigen::MatrixXd::Ones(points.cols(), reference_element_data.NumBasisFunctions);
185
186 for (unsigned int d = 0; d < reference_element_data.NumBasisFunctions; d++)
187 {
188 const Eigen::Vector3i &dofType = reference_element_data.DofTypes.col(d);
189 const Eigen::Vector3d &dofPosition = reference_element_data.DofPositions.col(d);
190
191 // terms of equation 1 - x - y - t * h
192 for (unsigned int t = 0; t < static_cast<unsigned int>(dofType[0]); t++)
193 {
194 values.col(d).array() *= (1.0 - x - y - t * h);
195 values.col(d) /= (1.0 - dofPosition.x() - dofPosition.y() - t * h);
196 }
197
198 // terms of equation x - t * h
199 for (unsigned int t = 0; t < static_cast<unsigned int>(dofType[1]); t++)
200 {
201 values.col(d).array() *= (x - t * h);
202 values.col(d) /= (dofPosition.x() - t * h);
203 }
204
205 // terms of equation y - t * h
206 for (unsigned int t = 0; t < static_cast<unsigned int>(dofType[2]); t++)
207 {
208 values.col(d).array() *= (y - t * h);
209 values.col(d) /= (dofPosition.y() - t * h);
210 }
211 }
212 return values;
213 }
214 }
215 }
216 // ***************************************************************************
217 std::vector<Eigen::MatrixXd> EvaluateBasisFunctionDerivatives(const Eigen::MatrixXd &points,
218 const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data &reference_element_data) const
219 {
220 switch (reference_element_data.Order)
221 {
222 case 0:
223 return std::vector<Eigen::MatrixXd>(reference_element_data.Dimension,
224 Eigen::MatrixXd::Zero(points.cols(), reference_element_data.NumBasisFunctions));
225 default: {
226 const double h = 1.0 / reference_element_data.Order;
227 const Eigen::ArrayXd x = points.row(0).transpose().array();
228 const Eigen::ArrayXd y = points.row(1).transpose().array();
229 std::vector<Eigen::MatrixXd> gradValues(reference_element_data.Dimension,
230 Eigen::MatrixXd::Zero(points.cols(), reference_element_data.NumBasisFunctions));
231
232 for (unsigned int d = 0; d < reference_element_data.NumBasisFunctions; d++)
233 {
234 const Eigen::Vector3i &dofType = reference_element_data.DofTypes.col(d);
235 const Eigen::Vector3d &dofPosition = reference_element_data.DofPositions.col(d);
236
237 const unsigned int numProds = dofType[0] + dofType[1] + dofType[2];
238
239 std::vector<Eigen::ArrayXd> prod_terms(numProds);
240 std::vector<Eigen::Array2d> grad_terms(numProds);
241 double denominator = 1.0;
242
243 unsigned int dt = 0;
244 // terms of equation 1 - x - y - t * h
245 for (unsigned int t = 0; t < static_cast<unsigned int>(dofType[0]); t++)
246 {
247 prod_terms[dt] = (1.0 - x - y - t * h);
248 grad_terms[dt] << -1.0, -1.0;
249 denominator *= (1.0 - dofPosition.x() - dofPosition.y() - t * h);
250 dt++;
251 }
252
253 // terms of equation x - t * h
254 for (unsigned int t = 0; t < static_cast<unsigned int>(dofType[1]); t++)
255 {
256 prod_terms[dt] = (x - t * h);
257 grad_terms[dt] << 1.0, 0.0;
258 denominator *= (dofPosition.x() - t * h);
259 dt++;
260 }
261
262 // terms of equation y - t * h
263 for (unsigned int t = 0; t < static_cast<unsigned int>(dofType[2]); t++)
264 {
265 prod_terms[dt] = (y - t * h);
266 grad_terms[dt] << 0.0, 1.0;
267 denominator *= (dofPosition.y() - t * h);
268 dt++;
269 }
270
271 for (unsigned int i = 0; i < numProds; i++)
272 {
273 Eigen::ArrayXd inner_prod = Eigen::ArrayXd::Ones(points.cols());
274 for (unsigned int j = 0; j < numProds; j++)
275 {
276 if (i != j)
277 inner_prod *= prod_terms[j];
278 }
279
280 gradValues[0].col(d).array() += inner_prod * grad_terms[i][0];
281 gradValues[1].col(d).array() += inner_prod * grad_terms[i][1];
282 }
283
284 gradValues[0].col(d) /= denominator;
285 gradValues[1].col(d) /= denominator;
286 }
287
288 return gradValues;
289 }
290 }
291 }
292 // ***************************************************************************
293 std::array<Eigen::MatrixXd, 4> EvaluateBasisFunctionSecondDerivatives(
294 const Eigen::MatrixXd &points,
295 const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data &reference_element_data) const
296 {
297 switch (reference_element_data.Order)
298 {
299 case 0:
300 case 1: {
301 const Eigen::MatrixXd zero_matrix = Eigen::MatrixXd::Zero(points.cols(), reference_element_data.NumBasisFunctions);
302 return {zero_matrix, zero_matrix, zero_matrix, zero_matrix};
303 }
304 case 2: {
305 std::array<Eigen::MatrixXd, 4> constant_laplacian;
306
307 for (unsigned int der = 0; der < 4; ++der)
308 constant_laplacian[der] = Eigen::MatrixXd::Zero(points.cols(), reference_element_data.NumBasisFunctions);
309
310 constant_laplacian[0].col(0) = Eigen::VectorXd::Constant(points.cols(), +4.0);
311 constant_laplacian[1].col(0) = Eigen::VectorXd::Constant(points.cols(), +4.0);
312 constant_laplacian[2].col(0) = Eigen::VectorXd::Constant(points.cols(), +4.0);
313 constant_laplacian[3].col(0) = Eigen::VectorXd::Constant(points.cols(), +4.0);
314
315 constant_laplacian[0].col(1) = Eigen::VectorXd::Constant(points.cols(), +4.0);
316 constant_laplacian[1].col(1) = Eigen::VectorXd::Constant(points.cols(), +0.0);
317 constant_laplacian[2].col(1) = Eigen::VectorXd::Constant(points.cols(), +0.0);
318 constant_laplacian[3].col(1) = Eigen::VectorXd::Constant(points.cols(), +0.0);
319
320 constant_laplacian[0].col(2) = Eigen::VectorXd::Constant(points.cols(), +0.0);
321 constant_laplacian[1].col(2) = Eigen::VectorXd::Constant(points.cols(), +0.0);
322 constant_laplacian[2].col(2) = Eigen::VectorXd::Constant(points.cols(), +0.0);
323 constant_laplacian[3].col(2) = Eigen::VectorXd::Constant(points.cols(), +4.0);
324
325 constant_laplacian[0].col(3) = Eigen::VectorXd::Constant(points.cols(), -8.0);
326 constant_laplacian[1].col(3) = Eigen::VectorXd::Constant(points.cols(), -4.0);
327 constant_laplacian[2].col(3) = Eigen::VectorXd::Constant(points.cols(), -4.0);
328 constant_laplacian[3].col(3) = Eigen::VectorXd::Constant(points.cols(), +0.0);
329
330 constant_laplacian[0].col(4) = Eigen::VectorXd::Constant(points.cols(), +0.0);
331 constant_laplacian[1].col(4) = Eigen::VectorXd::Constant(points.cols(), +4.0);
332 constant_laplacian[2].col(4) = Eigen::VectorXd::Constant(points.cols(), +4.0);
333 constant_laplacian[3].col(4) = Eigen::VectorXd::Constant(points.cols(), +0.0);
334
335 constant_laplacian[0].col(5) = Eigen::VectorXd::Constant(points.cols(), +0.0);
336 constant_laplacian[1].col(5) = Eigen::VectorXd::Constant(points.cols(), -4.0);
337 constant_laplacian[2].col(5) = Eigen::VectorXd::Constant(points.cols(), -4.0);
338 constant_laplacian[3].col(5) = Eigen::VectorXd::Constant(points.cols(), -8.0);
339
340 return constant_laplacian;
341 }
342 case 3: {
343 std::array<Eigen::MatrixXd, 4> laplacian;
344
345 for (unsigned int der = 0; der < 4; ++der)
346 laplacian[der] = Eigen::MatrixXd::Zero(points.cols(), reference_element_data.NumBasisFunctions);
347
348 const Eigen::ArrayXd x = points.row(0);
349 const Eigen::ArrayXd y = points.row(1);
350
351 laplacian[0].col(0) = 18.0 - 27.0 * y - 27.0 * x;
352 laplacian[1].col(0) = 18.0 - 27.0 * y - 27.0 * x;
353 laplacian[2].col(0) = 18.0 - 27.0 * y - 27.0 * x;
354 laplacian[3].col(0) = 18.0 - 27.0 * y - 27.0 * x;
355
356 laplacian[0].col(1) = 27.0 * x - 9;
357 laplacian[1].col(1) = Eigen::VectorXd::Constant(points.cols(), 0.0);
358 laplacian[2].col(1) = Eigen::VectorXd::Constant(points.cols(), 0.0);
359 laplacian[3].col(1) = Eigen::VectorXd::Constant(points.cols(), 0.0);
360
361 laplacian[0].col(2) = Eigen::VectorXd::Constant(points.cols(), 0.0);
362 laplacian[1].col(2) = Eigen::VectorXd::Constant(points.cols(), 0.0);
363 laplacian[2].col(2) = Eigen::VectorXd::Constant(points.cols(), 0.0);
364 laplacian[3].col(2) = 27.0 * y - 9;
365
366 laplacian[0].col(3) = 81.0 * x + 54.0 * y - 45.0;
367 laplacian[1].col(3) = 54.0 * x + 27.0 * y - 45.0 / 2.0;
368 laplacian[2].col(3) = 54.0 * x + 27.0 * y - 45.0 / 2.0;
369 laplacian[3].col(3) = 27.0 * x;
370
371 laplacian[0].col(4) = 36.0 - 27.0 * y - 81.0 * x;
372 laplacian[1].col(4) = 4.5 - 27.0 * x;
373 laplacian[2].col(4) = 4.5 - 27.0 * x;
374 laplacian[3].col(4) = Eigen::VectorXd::Constant(points.cols(), 0.0);
375
376 laplacian[0].col(5) = 27.0 * y;
377 laplacian[1].col(5) = 27.0 * x - 4.5;
378 laplacian[2].col(5) = 27.0 * x - 4.5;
379 laplacian[3].col(5) = Eigen::VectorXd::Constant(points.cols(), 0.0);
380
381 laplacian[0].col(6) = Eigen::VectorXd::Constant(points.cols(), 0.0);
382 laplacian[1].col(6) = 27.0 * y - 4.5;
383 laplacian[2].col(6) = 27.0 * y - 4.5;
384 laplacian[3].col(6) = 27.0 * x;
385
386 laplacian[0].col(7) = Eigen::VectorXd::Constant(points.cols(), 0.0);
387 laplacian[1].col(7) = 4.5 - 27.0 * y;
388 laplacian[2].col(7) = 4.5 - 27.0 * y;
389 laplacian[3].col(7) = 36.0 - 81.0 * y - 27.0 * x;
390
391 laplacian[0].col(8) = 27.0 * y;
392 laplacian[1].col(8) = 27.0 * x + 54.0 * y - 45.0 / 2.0;
393 laplacian[2].col(8) = 27.0 * x + 54.0 * y - 45.0 / 2.0;
394 laplacian[3].col(8) = 54.0 * x + 81.0 * y - 45.0;
395
396 laplacian[0].col(9) = -54.0 * y;
397 laplacian[1].col(9) = 27.0 - 54.0 * y - 54.0 * x;
398 laplacian[2].col(9) = 27.0 - 54.0 * y - 54.0 * x;
399 laplacian[3].col(9) = -54.0 * x;
400
401 return laplacian;
402 }
403 default: {
404 const Eigen::MatrixXd zero_matrix = Eigen::MatrixXd::Zero(points.cols(), reference_element_data.NumBasisFunctions);
405 return {zero_matrix, zero_matrix, zero_matrix, zero_matrix};
406 }
407 }
408 }
409};
410} // namespace PCC
411} // namespace FEM
412} // namespace Polydim
413
414#endif
static QuadratureData FillPointsAndWeights(const unsigned int &order)
Definition Quadrature_Gauss2D_Triangle.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
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:52
Eigen::MatrixXd EvaluateBasisFunctions(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data &reference_element_data) const
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:173
std::vector< Eigen::MatrixXd > EvaluateBasisFunctionDerivatives(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data &reference_element_data) const
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:217
FEM_Triangle_PCC_2D_ReferenceElement_Data Create(const unsigned int order) const
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:54
std::array< Eigen::MatrixXd, 4 > EvaluateBasisFunctionSecondDerivatives(const Eigen::MatrixXd &points, const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data &reference_element_data) const
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:293
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_Triangle_PCC_2D_ReferenceElement.hpp:28
Gedim::Quadrature::QuadratureData ReferenceTriangleQuadrature
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:39
Polydim::FEM::PCC::FEM_PCC_1D_ReferenceElement_Data BoundaryReferenceElement_Data
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:45
unsigned int NumDofs2D
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:33
unsigned int Order
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:30
unsigned int NumBasisFunctions
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:35
Eigen::VectorXd EdgeBasisCoefficients
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:48
Eigen::MatrixXd DofPositions
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:36
unsigned int NumDofs0D
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:31
unsigned int NumDofs1D
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:32
std::array< Eigen::MatrixXd, 4 > ReferenceBasisFunctionSecondDerivativeValues
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:43
std::vector< Eigen::MatrixXd > ReferenceBasisFunctionDerivativeValues
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:42
unsigned int Dimension
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:29
Eigen::MatrixXd ReferenceBasisFunctionValues
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:41
Eigen::RowVectorXd EdgeInternalPoints
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:47
Eigen::MatrixXi DofTypes
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:37
Definition VEM_PCC_Utilities.hpp:37
Eigen::VectorXd ComputeEdgeBasisCoefficients(const unsigned int &order, const Eigen::VectorXd &edgeInternalPoints) const
Definition VEM_PCC_Utilities.hpp:38