PolyDiM
C++ library for POLYtopal DIscretization Methods
Loading...
Searching...
No Matches
ZFEM_PCC_Utilities.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 __ZFEM_PCC_Utilities_HPP
13#define __ZFEM_PCC_Utilities_HPP
14
15#include "Eigen/Eigen"
18#include <algorithm>
19#include <numeric>
20
21namespace Polydim
22{
23namespace ZFEM
24{
25namespace PCC
26{
27
29{
30 Eigen::VectorXd ComputeEdgeBasisCoefficients(const unsigned int &order, const Eigen::VectorXd &edgeInternalPoints) const
31 {
32 // Compute basis function coefficients on the generic edge.
33 Eigen::VectorXd interpolation_points_x(order + 1);
34 interpolation_points_x << 0.0, 1.0, edgeInternalPoints;
35 return Interpolation::Lagrange::Lagrange_1D_coefficients(interpolation_points_x);
36 }
37
38 Eigen::MatrixXd ComputeValuesOnEdge(const Eigen::RowVectorXd &edgeInternalPoints,
39 const unsigned int &order,
40 const Eigen::VectorXd &edgeBasisCoefficients,
41 const Eigen::VectorXd &pointsCurvilinearCoordinates) const
42 {
43 Eigen::VectorXd interpolation_points_x(order + 1);
44 interpolation_points_x << 0.0, 1.0, edgeInternalPoints.transpose();
45 return Interpolation::Lagrange::Lagrange_1D_values(interpolation_points_x, edgeBasisCoefficients, pointsCurvilinearCoordinates);
46 }
47
48 inline Eigen::MatrixXd ComputeBasisFunctionsValues(const unsigned int &NumBasisFunctions,
49 const unsigned int &NumVirtualBasisFunctions,
50 const Eigen::MatrixXd &fem_basis_functions_values,
51 const Eigen::MatrixXd &VirtualWeights) const
52 {
53 return fem_basis_functions_values.leftCols(NumBasisFunctions) +
54 fem_basis_functions_values.rightCols(NumVirtualBasisFunctions) * VirtualWeights.transpose();
55 }
56
57 inline Eigen::MatrixXd ComputeFEMBasisFunctionsValues(const ZFEM_PCC_2D_ReferenceElement_Data &reference_element_data,
58 const unsigned int &num_basis_functions,
59 const unsigned int &num_virtual_basis_functions,
60 const std::vector<Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data> &fem_local_space_data,
61 const Eigen::MatrixXi &local_to_global) const
62 {
64 const unsigned int num_quadrature =
66 const unsigned int num_triangles = fem_local_space_data.size();
67
68 Eigen::MatrixXd total_fem_basis_functions_values =
69 Eigen::MatrixXd::Zero(num_quadrature * num_triangles, num_basis_functions + num_virtual_basis_functions);
70
71 unsigned int offeset_quadrature_points = 0;
72 for (unsigned int t = 0; t < num_triangles; t++)
73 {
74 const Eigen::MatrixXd fem_basis_function_values =
75 fem_local_space.ComputeBasisFunctionsValues(reference_element_data.fem_reference_element_data,
76 fem_local_space_data[t]);
77
78 for (unsigned int p = 0; p < local_to_global.cols(); p++)
79 total_fem_basis_functions_values.block(offeset_quadrature_points, local_to_global(t, p), num_quadrature, 1) =
80 fem_basis_function_values.col(p);
81
82 offeset_quadrature_points += num_quadrature;
83 }
84
85 return total_fem_basis_functions_values;
86 }
87
88 inline Eigen::MatrixXd ComputeFEMBasisFunctionsValues(const ZFEM_PCC_2D_ReferenceElement_Data &reference_element_data,
89 const unsigned int &num_basis_functions,
90 const unsigned int &num_virtual_basis_functions,
91 const std::vector<Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data> &fem_local_space_data,
92 const Eigen::MatrixXi &local_to_global,
93 const std::vector<Eigen::MatrixXd> &points) const
94 {
96 unsigned int num_quadrature = 0;
97
98 for (unsigned int t = 0; t < points.size(); t++)
99 num_quadrature += points[t].cols();
100
101 Eigen::MatrixXd total_fem_basis_functions_values =
102 Eigen::MatrixXd::Zero(num_quadrature, num_basis_functions + num_virtual_basis_functions);
103
104 unsigned int offeset_quadrature_points = 0;
105 for (unsigned int t = 0; t < points.size(); t++)
106 {
107 if (points[t].size() > 0)
108 {
109
110 const unsigned int num_ref_quadrature = points[t].cols();
111
112 const Eigen::MatrixXd fem_basis_function_values =
113 fem_local_space.ComputeBasisFunctionsValues(reference_element_data.fem_reference_element_data,
114 fem_local_space_data[t],
115 points[t]);
116
117 for (unsigned int p = 0; p < local_to_global.cols(); p++)
118 total_fem_basis_functions_values.block(offeset_quadrature_points, local_to_global(t, p), num_ref_quadrature, 1) =
119 fem_basis_function_values.col(p);
120
121 offeset_quadrature_points += num_ref_quadrature;
122 }
123 }
124
125 return total_fem_basis_functions_values;
126 }
127
128 inline std::vector<Eigen::MatrixXd> ComputeFEMBasisFunctionsDerivativeValues(
129 unsigned int dimension,
130 const ZFEM_PCC_2D_ReferenceElement_Data &reference_element_data,
131 const unsigned int &num_basis_functions,
132 const unsigned int &num_virtual_basis_functions,
133 const std::vector<Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data> &fem_local_space_data,
134 const Eigen::MatrixXi &local_to_global) const
135 {
137 const unsigned int num_quadrature =
139 const unsigned int num_triangles = fem_local_space_data.size();
140
141 std::vector<Eigen::MatrixXd> total_fem_basis_functions_derivative_values(
142 dimension,
143 Eigen::MatrixXd::Zero(num_quadrature * num_triangles, num_basis_functions + num_virtual_basis_functions));
144
145 unsigned int offeset_quadrature_points = 0;
146 for (unsigned int t = 0; t < num_triangles; t++)
147 {
148
149 const std::vector<Eigen::MatrixXd> fem_basis_function_derivatives_values =
150 fem_local_space.ComputeBasisFunctionsDerivativeValues(reference_element_data.fem_reference_element_data,
151 fem_local_space_data[t]);
152
153 for (unsigned int d = 0; d < dimension; d++)
154 {
155 for (unsigned int p = 0; p < local_to_global.cols(); p++)
156 total_fem_basis_functions_derivative_values[d].block(offeset_quadrature_points, local_to_global(t, p), num_quadrature, 1) =
157 fem_basis_function_derivatives_values[d].col(p);
158 }
159
160 offeset_quadrature_points += num_quadrature;
161 }
162
163 return total_fem_basis_functions_derivative_values;
164 }
165
166 inline std::vector<Eigen::MatrixXd> ComputeFEMBasisFunctionsDerivativeValues(
167 unsigned int dimension,
168 const ZFEM_PCC_2D_ReferenceElement_Data &reference_element_data,
169 const unsigned int &num_basis_functions,
170 const unsigned int &num_virtual_basis_functions,
171 const std::vector<Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data> &fem_local_space_data,
172 const Eigen::MatrixXi &local_to_global,
173 const std::vector<Eigen::MatrixXd> &points) const
174 {
176 unsigned int num_quadrature = 0;
177
178 for (unsigned int t = 0; t < points.size(); t++)
179 num_quadrature += points[t].cols();
180
181 std::vector<Eigen::MatrixXd> total_fem_basis_functions_derivative_values(
182 dimension,
183 Eigen::MatrixXd::Zero(num_quadrature, num_basis_functions + num_virtual_basis_functions));
184
185 unsigned int offeset_quadrature_points = 0;
186 for (unsigned int t = 0; t < points.size(); t++)
187 {
188 if (points[t].size() > 0)
189 {
190
191 const unsigned int num_ref_quadrature = points[t].cols();
192
193 const std::vector<Eigen::MatrixXd> fem_basis_function_derivatives_values =
194 fem_local_space.ComputeBasisFunctionsDerivativeValues(reference_element_data.fem_reference_element_data,
195 fem_local_space_data[t],
196 points[t]);
197
198 for (unsigned int d = 0; d < dimension; d++)
199 {
200 for (unsigned int p = 0; p < local_to_global.cols(); p++)
201 total_fem_basis_functions_derivative_values[d].block(offeset_quadrature_points,
202 local_to_global(t, p),
203 num_ref_quadrature,
204 1) =
205 fem_basis_function_derivatives_values[d].col(p);
206 }
207
208 offeset_quadrature_points += num_ref_quadrature;
209 }
210 }
211
212 return total_fem_basis_functions_derivative_values;
213 }
214
215 inline std::vector<Eigen::MatrixXd> ComputeBasisFunctionsDerivativeValues(const unsigned int &Dimension,
216 const unsigned int &NumBasisFunctions,
217 const unsigned int &NumVirtualBasisFunctions,
218 const std::vector<Eigen::MatrixXd> &fem_basis_functions_derivative_values,
219 const Eigen::MatrixXd &VirtualWeights) const
220 {
221 std::vector<Eigen::MatrixXd> ZFEM_basis_functions_derivative_values(Dimension);
222
223 for (unsigned int d = 0; d < Dimension; d++)
224 {
225 ZFEM_basis_functions_derivative_values[d] =
226 fem_basis_functions_derivative_values[d].leftCols(NumBasisFunctions) +
227 fem_basis_functions_derivative_values[d].rightCols(NumVirtualBasisFunctions) * VirtualWeights.transpose();
228 }
229
230 return ZFEM_basis_functions_derivative_values;
231 }
232
233 Eigen::MatrixXi CreateMaps(const unsigned int order,
234 const unsigned int num_vertices,
235 const unsigned int NumDOFs1D,
236 const unsigned int NumDOFs2D,
237 const unsigned int NumBasisFunctions) const
238 {
239 Eigen::MatrixXi local_to_total(num_vertices, 3 * (1 + NumDOFs1D) + NumDOFs2D);
240
241 const Eigen::ArrayXi edge_reference_id_dofs = Eigen::VectorXi::LinSpaced(NumDOFs1D, 0, NumDOFs1D - 1);
242
243 // Vertex and boundary DOFs
244 for (unsigned int t = 0; t < num_vertices; t++)
245 {
246 const unsigned int next_t = (t + 1) % num_vertices;
247
248 local_to_total(t, 1) = t;
249 local_to_total(t, 2) = next_t;
250 local_to_total.row(t).segment(3 + NumDOFs1D, NumDOFs1D) = edge_reference_id_dofs + t * NumDOFs1D + num_vertices;
251 }
252
253 if (order <= 2)
254 {
255 local_to_total.col(0) = Eigen::VectorXi::Constant(num_vertices, NumBasisFunctions);
256
257 for (unsigned int t = 0; t < num_vertices; t++)
258 {
259 const unsigned int next_t = (t + 1) % num_vertices;
260
261 local_to_total.row(t).segment(3, NumDOFs1D) = edge_reference_id_dofs + NumBasisFunctions + 1 + t * NumDOFs1D;
262 local_to_total.row(t).segment(3 + 2 * NumDOFs1D, NumDOFs1D) =
263 edge_reference_id_dofs + NumBasisFunctions + 1 + next_t * NumDOFs1D;
264 }
265 }
266 else if (order == 3)
267 {
268 local_to_total.col(0) = Eigen::VectorXi::Constant(num_vertices, NumBasisFunctions - 1);
269
270 for (unsigned int t = 0; t < num_vertices; t++)
271 {
272 const unsigned int next_t = (t + 1) % num_vertices;
273
274 local_to_total.row(t).segment(3, NumDOFs1D) = edge_reference_id_dofs + NumBasisFunctions + t * NumDOFs1D;
275 local_to_total.row(t).segment(3 + 2 * NumDOFs1D, NumDOFs1D) =
276 edge_reference_id_dofs + NumBasisFunctions + next_t * NumDOFs1D;
277 local_to_total(t, 3 + 3 * NumDOFs1D) = NumBasisFunctions + num_vertices * NumDOFs1D + t;
278 }
279 }
280 else
281 {
282 local_to_total.col(0) = Eigen::VectorXi::Constant(num_vertices, NumBasisFunctions - NumDOFs2D);
283
284 const unsigned int base = (NumDOFs2D - 1) / num_vertices;
285 const unsigned int other = (NumDOFs2D - 1) % num_vertices;
286
287 std::vector<unsigned int> num_pt_triangle(num_vertices, 0);
288
289 const unsigned int num_selected_triangles = NumDOFs2D - 1;
290
291 unsigned int count = 0;
292 const unsigned int repeat_times = ceil(num_vertices / ((double)num_selected_triangles));
293 for (unsigned int i = 0; i < repeat_times; i++)
294 {
295 for (unsigned int j = 0; j < num_selected_triangles; j++)
296 {
297 if (i + j * repeat_times < num_vertices && count < num_vertices)
298 {
299 num_pt_triangle[i + j * repeat_times] = base + (count < other ? 1 : 0);
300 count++;
301 }
302 }
303 }
304
305 unsigned int offset_internal = NumBasisFunctions + num_vertices * NumDOFs1D;
306 unsigned int offset_internal_dof = NumBasisFunctions - NumDOFs2D + 1;
307
308 std::vector<unsigned int> copy_ordered(NumDOFs2D);
309 std::iota(copy_ordered.begin(), copy_ordered.end(), 0);
310
311 std::vector<unsigned int> p_mod(NumDOFs2D);
312 for (unsigned int t = 0; t < num_vertices; t++)
313 {
314 const unsigned int next_t = (t + 1) % num_vertices;
315
316 local_to_total.row(t).segment(3, NumDOFs1D) = edge_reference_id_dofs + NumBasisFunctions + t * NumDOFs1D;
317 local_to_total.row(t).segment(3 + 2 * NumDOFs1D, NumDOFs1D) =
318 edge_reference_id_dofs + NumBasisFunctions + next_t * NumDOFs1D;
319
320 if (NumDOFs2D > 1 && num_pt_triangle[t] > 0)
321 {
322 unsigned int count = 0;
323 const unsigned int repeat_times = ceil(((double)NumDOFs2D) / num_pt_triangle[t]);
324 for (unsigned int i = 0; i < repeat_times; i++)
325 {
326 for (unsigned int j = 0; j < num_pt_triangle[t]; j++)
327 {
328 if (i + j * repeat_times < NumDOFs2D && count < NumDOFs2D)
329 p_mod[count++] = (i + j * repeat_times + t + 1) % NumDOFs2D;
330 }
331 }
332 }
333 else
334 p_mod = copy_ordered;
335
336 for (unsigned int p = 0; p < num_pt_triangle[t]; p++)
337 {
338 local_to_total(t, 3 * (NumDOFs1D + 1) + p_mod[p]) = offset_internal_dof;
339 offset_internal_dof += 1;
340 }
341
342 for (unsigned int p = num_pt_triangle[t]; p < NumDOFs2D; p++)
343 {
344 local_to_total(t, 3 * (NumDOFs1D + 1) + p_mod[p]) = offset_internal;
345 offset_internal += 1;
346 }
347 }
348 }
349
350 return local_to_total;
351 }
352
353 void ComputeMinimizerSumOfSquaredWeightsMonomials(const Eigen::MatrixXd &Dmatrix,
354 const Eigen::MatrixXd &VanderVirtuals,
355 Eigen::MatrixXd &weights) const
356 {
357 const Eigen::MatrixXd Mmatrix = Dmatrix.transpose() * Dmatrix;
358 const Eigen::LLT<Eigen::MatrixXd> Mmatrix_LLT = Mmatrix.llt();
359
360 weights = Dmatrix * Mmatrix_LLT.solve(VanderVirtuals.transpose());
361 }
362};
363} // namespace PCC
364} // namespace ZFEM
365} // namespace Polydim
366
367#endif
Definition FEM_Triangle_PCC_2D_LocalSpace.hpp:27
std::vector< Eigen::MatrixXd > ComputeBasisFunctionsDerivativeValues(const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data &reference_element_data, const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data &local_space) const
Definition FEM_Triangle_PCC_2D_LocalSpace.hpp:103
Eigen::MatrixXd ComputeBasisFunctionsValues(const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data &reference_element_data, const Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data &local_space) const
Definition FEM_Triangle_PCC_2D_LocalSpace.hpp:55
Eigen::VectorXd Lagrange_1D_coefficients(const Eigen::VectorXd &interpolation_points_x)
Compute the barycentric weights of the 1D Lagrange basis.
Definition lagrange_1D.cpp:21
Eigen::MatrixXd Lagrange_1D_values(const Eigen::VectorXd &interpolation_points_x, const Eigen::VectorXd &lagrange_1D_coefficients, const Eigen::VectorXd &evaluation_points_x)
Evaluate the 1D Lagrange basis functions at given points.
Definition lagrange_1D.cpp:55
Definition FEM_MCC_2D_LocalSpace.cpp:17
Eigen::MatrixXd Points
Definition QuadratureData.hpp:23
Gedim::Quadrature::QuadratureData ReferenceTriangleQuadrature
Definition FEM_Triangle_PCC_2D_ReferenceElement.hpp:39
Reference-element data for the 2D primal conforming ZFEM (Zipped FEM) space.
Definition I_ZFEM_PCC_2D_ReferenceElement.hpp:36
Polydim::FEM::PCC::FEM_Triangle_PCC_2D_ReferenceElement_Data fem_reference_element_data
Definition I_ZFEM_PCC_2D_ReferenceElement.hpp:43
Definition ZFEM_PCC_Utilities.hpp:29
Eigen::MatrixXi CreateMaps(const unsigned int order, const unsigned int num_vertices, const unsigned int NumDOFs1D, const unsigned int NumDOFs2D, const unsigned int NumBasisFunctions) const
Definition ZFEM_PCC_Utilities.hpp:233
void ComputeMinimizerSumOfSquaredWeightsMonomials(const Eigen::MatrixXd &Dmatrix, const Eigen::MatrixXd &VanderVirtuals, Eigen::MatrixXd &weights) const
Definition ZFEM_PCC_Utilities.hpp:353
Eigen::MatrixXd ComputeBasisFunctionsValues(const unsigned int &NumBasisFunctions, const unsigned int &NumVirtualBasisFunctions, const Eigen::MatrixXd &fem_basis_functions_values, const Eigen::MatrixXd &VirtualWeights) const
Definition ZFEM_PCC_Utilities.hpp:48
Eigen::VectorXd ComputeEdgeBasisCoefficients(const unsigned int &order, const Eigen::VectorXd &edgeInternalPoints) const
Definition ZFEM_PCC_Utilities.hpp:30
std::vector< Eigen::MatrixXd > ComputeFEMBasisFunctionsDerivativeValues(unsigned int dimension, const ZFEM_PCC_2D_ReferenceElement_Data &reference_element_data, const unsigned int &num_basis_functions, const unsigned int &num_virtual_basis_functions, const std::vector< Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data > &fem_local_space_data, const Eigen::MatrixXi &local_to_global, const std::vector< Eigen::MatrixXd > &points) const
Definition ZFEM_PCC_Utilities.hpp:166
Eigen::MatrixXd ComputeFEMBasisFunctionsValues(const ZFEM_PCC_2D_ReferenceElement_Data &reference_element_data, const unsigned int &num_basis_functions, const unsigned int &num_virtual_basis_functions, const std::vector< Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data > &fem_local_space_data, const Eigen::MatrixXi &local_to_global, const std::vector< Eigen::MatrixXd > &points) const
Definition ZFEM_PCC_Utilities.hpp:88
Eigen::MatrixXd ComputeValuesOnEdge(const Eigen::RowVectorXd &edgeInternalPoints, const unsigned int &order, const Eigen::VectorXd &edgeBasisCoefficients, const Eigen::VectorXd &pointsCurvilinearCoordinates) const
Definition ZFEM_PCC_Utilities.hpp:38
std::vector< Eigen::MatrixXd > ComputeFEMBasisFunctionsDerivativeValues(unsigned int dimension, const ZFEM_PCC_2D_ReferenceElement_Data &reference_element_data, const unsigned int &num_basis_functions, const unsigned int &num_virtual_basis_functions, const std::vector< Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data > &fem_local_space_data, const Eigen::MatrixXi &local_to_global) const
Definition ZFEM_PCC_Utilities.hpp:128
Eigen::MatrixXd ComputeFEMBasisFunctionsValues(const ZFEM_PCC_2D_ReferenceElement_Data &reference_element_data, const unsigned int &num_basis_functions, const unsigned int &num_virtual_basis_functions, const std::vector< Polydim::FEM::PCC::FEM_Triangle_PCC_2D_LocalSpace_Data > &fem_local_space_data, const Eigen::MatrixXi &local_to_global) const
Definition ZFEM_PCC_Utilities.hpp:57
std::vector< Eigen::MatrixXd > ComputeBasisFunctionsDerivativeValues(const unsigned int &Dimension, const unsigned int &NumBasisFunctions, const unsigned int &NumVirtualBasisFunctions, const std::vector< Eigen::MatrixXd > &fem_basis_functions_derivative_values, const Eigen::MatrixXd &VirtualWeights) const
Definition ZFEM_PCC_Utilities.hpp:215