HArD::Core3D
Hybrid Arbitrary Degree::Core 3D - Library to implement 3D schemes with vertex, edge, face and cell polynomials as unknowns
GMpoly_face.hpp
Go to the documentation of this file.
1 # ifndef _GMPOLY_FACE_HPP
2 # define _GMPOLY_FACE_HPP
3 
4 /*
5 
6  Classes to implement the quadrature-free polynomial integration rules
7 
8 */
9 
10 #include <cassert>
11 #include <cmath>
12 
13 #include <algorithm>
14 #include <array>
15 #include <iostream>
16 #include <vector>
17 #include <unordered_map>
18 
19 #include <mesh.hpp>
20 #include <quadraturerule.hpp>
21 #include <basis.hpp>
22 #include <typeinfo>
23 
24 #include <GMpoly_cell.hpp>
25 
26 namespace HArDCore3D {
27 
34 //----------------------------------------------------------------------
35 //----------------------------------------------------------------------
36 // INTEGRALS OF MONOMIALS
37 //----------------------------------------------------------------------
38 //----------------------------------------------------------------------
39 
42 {
43  size_t operator()(const Eigen::Vector2i & p) const
44  {
45  constexpr size_t b = 100; // max degree must be less than the basis b
46  return p(0) + p(1) * b;
47  }
48 };
49 
51 typedef std::unordered_map<Eigen::Vector2i, double, VecFaceHash> MonomialFaceIntegralsType;
52 
54 std::vector<MonomialFaceIntegralsType> IntegrateFaceMonomials_onEdges
55  (const Face & F,
56  const size_t maxdeg
57  );
58 
61  (const Face & F,
62  const int maxdeg
63  );
64 
67  (const Face & F,
68  const size_t degree,
69  const MonomialFaceIntegralsType & mono_int_map = {}
70  );
71 
72 
73 //----------------------------------------------------------------------
74 //----------------------------------------------------------------------
75 // FUNCTIONS TO COMPUTE GRAM MATRICES
76 //----------------------------------------------------------------------
77 //----------------------------------------------------------------------
78 
79 //
80 /* BASIC ONES: Monomial, tensorized, and generic template */
81 
83 template<typename BasisType1, typename BasisType2>
84 Eigen::MatrixXd GramMatrix(const Face& F,
85  const BasisType1 & basis1,
86  const BasisType2 & basis2,
87  MonomialFaceIntegralsType mono_int_map = {}
88  )
89  {
90  // If no ancestor is to be used, we shouldn't be in this overload
91  static_assert(useAncestor<BasisType1>() || useAncestor<BasisType2>(), "No method to compute this Gram matrix");
92 
93  if constexpr (!useAncestor<BasisType1>() && useAncestor<BasisType2>()) {
94  return transformGM(basis2, 'C', GramMatrix(F, basis1, basis2.ancestor(), mono_int_map) );
95  } else if constexpr (useAncestor<BasisType1>() && !useAncestor<BasisType2>()) {
96  return transformGM(basis1, 'R', GramMatrix(F, basis1.ancestor(), basis2, mono_int_map) );
97  } else {
98  return transformGM(basis1, 'R', transformGM(basis2, 'C', GramMatrix(F, basis1.ancestor(), basis2.ancestor(), mono_int_map) ) );
99  }
100 
101  }
102 
104 Eigen::MatrixXd GramMatrix(
105  const Face & F,
106  const MonomialScalarBasisFace & basis1,
107  const MonomialScalarBasisFace & basis2,
108  MonomialFaceIntegralsType mono_int_map = {}
109  );
110 
112 template<typename BasisType>
113 Eigen::MatrixXd GramMatrix(const Face& F, const BasisType & basis, MonomialFaceIntegralsType mono_int_map = {})
114  {
115  return GramMatrix(F, basis, basis, mono_int_map);
116  }
117 
119 template<typename BasisType1, typename BasisType2, size_t N>
120 Eigen::MatrixXd GramMatrix(
121  const Face& F,
124  MonomialFaceIntegralsType mono_int_map = {}
125  )
126  {
127  Eigen::MatrixXd gm = Eigen::MatrixXd::Zero(basis1.dimension(), basis2.dimension());
128 
129  Eigen::MatrixXd anc_gm = GramMatrix(F, basis1.ancestor(), basis2.ancestor(), mono_int_map);
130  size_t dim1 = anc_gm.rows();
131  size_t dim2 = anc_gm.cols();
132 
133  for (size_t i=0; i<N; i++){
134  gm.block(i*dim1, i*dim2, dim1, dim2) = anc_gm;
135  }
136  return gm;
137  }
138 
140 template<typename BasisType1, typename BasisType2>
141 Eigen::MatrixXd GramMatrix(
142  const Face & F,
143  const TangentFamily<BasisType1> & basis1,
144  const TangentFamily<BasisType2> & basis2,
145  MonomialFaceIntegralsType mono_int_map = {}
146  )
147  {
148  Eigen::MatrixXd gm(basis1.dimension(), basis2.dimension());
149 
150  Eigen::MatrixXd anc_gm = GramMatrix(F, basis1.ancestor(), basis2.ancestor(), mono_int_map);
151  size_t dim1 = anc_gm.rows();
152  size_t dim2 = anc_gm.cols();
153 
154  Eigen::Matrix<double, 2, 3> generators1 = basis1.generators();
155  Eigen::Matrix<double, 2, 3> generators2 = basis2.generators();
156 
157  for (size_t i=0; i<2; i++) {
158  for (size_t j=0; j<2; j++) {
159  gm.block(i*dim1, j*dim2, dim1, dim2) = generators1.row(i).dot(generators2.row(j)) * anc_gm;
160  }
161  }
162 
163  return gm;
164  }
165 
167 Eigen::MatrixXd GramMatrix(
168  const Face & F,
169  const RolyComplBasisFace & basis1,
170  const RolyComplBasisFace & basis2,
171  MonomialFaceIntegralsType mono_int_map = {}
172  );
173 
175 Eigen::MatrixXd GramMatrix(
176  const Face & F,
177  const GolyComplBasisFace & basis1,
178  const GolyComplBasisFace & basis2,
179  MonomialFaceIntegralsType mono_int_map = {}
180  );
181 
183 template<typename BasisType>
184 Eigen::MatrixXd GramMatrix(
185  const Face & F,
186  const RolyComplBasisFace & basis1,
187  const TangentFamily<BasisType> & basis2,
188  MonomialFaceIntegralsType mono_int_map = {}
189  )
190  {
191  size_t dim1 = basis1.dimension();
192  size_t dim2 = basis2.dimension()/2;
193  size_t totaldegree = basis1.max_degree()+basis2.max_degree();
194  Eigen::MatrixXd gm = Eigen::MatrixXd::Zero(dim1, 2*dim2);
195 
196  // Obtain integration data from IntegrateFaceMonomials
197  MonomialFaceIntegralsType intmap = CheckIntegralsDegree(F, totaldegree, mono_int_map);
198 
199  std::vector<Eigen::MatrixXd> gmrs = {GMRolyComplScalar(F, basis1, basis2.ancestor(), 0, intmap), GMRolyComplScalar(F, basis1, basis2.ancestor(), 1, intmap)};
200  Eigen::Matrix<double, 2, 3> jacobian1 = basis1.jacobian();
201  Eigen::Matrix<double, 2, 3> generators2 = basis2.generators();
202  Eigen::Matrix2d W = jacobian1 * generators2.transpose();
203 
204  for (size_t k=0; k<2; k++) {
205  for (size_t j=0; j<2; j++) {
206  gm.block(0, j*dim2, dim1, dim2) += W(k,j) * gmrs[k];
207  }
208  }
209 
210  return F.diam() * gm;
211  }
212 
214 template<typename BasisType>
215 Eigen::MatrixXd GramMatrix(
216  const Face & F,
217  const TangentFamily<BasisType> & basis1,
218  const RolyComplBasisFace & basis2,
219  MonomialFaceIntegralsType mono_int_map = {}
220  )
221  {
222  return GramMatrix(F, basis2, basis1, mono_int_map).transpose();
223  }
224 
226 Eigen::MatrixXd GMRolyComplScalar(
227  const Face & F,
228  const RolyComplBasisFace & rolycompl_basis,
229  const MonomialScalarBasisFace & mono_basis,
230  const size_t m,
231  MonomialFaceIntegralsType mono_int_map = {}
232  );
233 
235 template<typename BasisType>
236 Eigen::MatrixXd GMRolyComplScalar(
237  const Face & F,
238  const RolyComplBasisFace & basis1,
239  const BasisType & basis2,
240  const size_t m,
241  MonomialFaceIntegralsType mono_int_map = {}
242  )
243  {
244  // If no ancestor is to be used, we shouldn't be in this overload
245  static_assert(BasisType::hasAncestor, "No method to compute this Gram matrix of derivatives");
246  return transformGM(basis2, 'C', GMRolyComplScalar(F, basis1, basis2.ancestor(), m, mono_int_map) );
247  }
248 
250 Eigen::MatrixXd GMScalarDerivative(
251  const Face & F,
252  const MonomialScalarBasisFace & basis1,
253  const MonomialScalarBasisFace & basis2,
254  const size_t m,
255  MonomialFaceIntegralsType mono_int_map = {}
256  );
257 
259 Eigen::MatrixXd GMScalarDerivative(
260  const Face & F,
261  const MonomialScalarBasisFace & basis1,
262  const MonomialScalarBasisFace & basis2,
263  const size_t m,
264  const size_t l,
265  MonomialFaceIntegralsType mono_int_map = {}
266  );
267 
269 template<typename BasisType1, typename BasisType2>
270 Eigen::MatrixXd GMScalarDerivative(
271  const Face& F,
272  const BasisType1 & basis1,
273  const BasisType2 & basis2,
274  const size_t m,
275  MonomialFaceIntegralsType mono_int_map = {}
276  )
277  {
278  // If no ancestor is to be used, we shouldn't be in this overload
279  static_assert(BasisType1::hasAncestor || BasisType2::hasAncestor, "No method to compute this Gram matrix of derivatives");
280 
281  if constexpr (!BasisType1::hasAncestor && BasisType2::hasAncestor) {
282  return transformGM(basis2, 'C', GMScalarDerivative(F, basis1, basis2.ancestor(), m, mono_int_map) );
283  } else if constexpr (BasisType1::hasAncestor && !BasisType2::hasAncestor) {
284  return transformGM(basis1, 'R', GMScalarDerivative(F, basis1.ancestor(), basis2, m, mono_int_map) );
285  } else {
286  return transformGM(basis1, 'R', transformGM(basis2, 'C', GMScalarDerivative(F, basis1.ancestor(), basis2.ancestor(), m, mono_int_map) ) );
287  }
288  }
289 
291 template<typename BasisType1, typename BasisType2>
292 Eigen::MatrixXd GMScalarDerivative(
293  const Face& F,
294  const BasisType1 & basis1,
295  const BasisType2 & basis2,
296  const size_t m,
297  const size_t l,
298  MonomialFaceIntegralsType mono_int_map = {}
299  )
300  {
301  // If no ancestor is to be used, we shouldn't be in this overload
302  static_assert(BasisType1::hasAncestor || BasisType2::hasAncestor, "No method to compute this Gram matrix of derivatives");
303 
304  if constexpr (!BasisType1::hasAncestor && BasisType2::hasAncestor) {
305  return transformGM(basis2, 'C', GMScalarDerivative(F, basis1, basis2.ancestor(), m, l, mono_int_map) );
306  } else if constexpr (BasisType1::hasAncestor && !BasisType2::hasAncestor) {
307  return transformGM(basis1, 'R', GMScalarDerivative(F, basis1.ancestor(), basis2, m, l, mono_int_map) );
308  } else {
309  return transformGM(basis1, 'R', transformGM(basis2, 'C', GMScalarDerivative(F, basis1.ancestor(), basis2.ancestor(), m, l, mono_int_map) ) );
310  }
311 
312  }
313 
315 template<typename BasisType1, typename BasisType2>
316 Eigen::MatrixXd GramMatrix(
317  const Face & F,
318  const CurlBasis<BasisType1> & basis1,
319  const CurlBasis<BasisType2> & basis2,
320  MonomialFaceIntegralsType mono_int_map = {}
321  )
322  {
323  // Dimension of the gram matrix
324  size_t dim1 = basis1.dimension();
325  size_t dim2 = basis2.dimension();
326  size_t totaldegree = basis1.ancestor().max_degree()+basis2.ancestor().max_degree()-2;
327  Eigen::MatrixXd gm = Eigen::MatrixXd::Zero(dim1,dim2);
328 
329  // Obtain integration data from IntegrateFaceMonomials
330  MonomialFaceIntegralsType intmap = CheckIntegralsDegree(F, totaldegree, mono_int_map);
331 
332  for (size_t m=0; m<2; m++){
333  gm += GMScalarDerivative(F, basis1.ancestor(), basis2.ancestor(), m, m, intmap);
334  }
335 
336  return gm/std::pow(F.diam(), 2);
337  }
338 
340 template<typename BasisType1, typename BasisType2>
341 Eigen::MatrixXd GramMatrix(
342  const Face & F,
343  const CurlBasis<BasisType1> & basis1,
344  const TangentFamily<BasisType2> & basis2,
345  MonomialFaceIntegralsType mono_int_map = {}
346  )
347  {
348  // Dimension of the gram matrix
349  size_t dim1 = basis1.dimension();
350  size_t dim2 = basis2.dimension()/2;
351  size_t totaldegree = basis1.ancestor().max_degree()+basis2.max_degree()-1;
352  Eigen::MatrixXd gm = Eigen::MatrixXd::Zero(dim1,dim2*2);
353 
354  // Obtain integration data from IntegrateFaceMonomials
355  MonomialFaceIntegralsType intmap = CheckIntegralsDegree(F, totaldegree, mono_int_map);
356 
357  std::vector<Eigen::MatrixXd> gmd = {GMScalarDerivative(F, basis1.ancestor(), basis2.ancestor(), 0, intmap), GMScalarDerivative(F, basis1.ancestor(), basis2.ancestor(), 1, intmap)};
358  // JF must be the jacobian (change of variable 3D->2D) of a scalar basis on the face (underlying basis1, perhaps after
359  // several derived bases). We create one to make sure we capture the correct jacobian
360  MonomialScalarBasisFace mono_P0_F(F, 0);
361  Eigen::Matrix<double, 2, 3> JF = mono_P0_F.jacobian();
362  VectorRd nF = F.normal();
363  Eigen::Matrix<double, 2, 3> generators2 = basis2.generators();
364  Eigen::Matrix2d W;
365  W.col(0) = JF * nF.cross(generators2.row(0));
366  W.col(1) = JF * nF.cross(generators2.row(1));
367 
368  for (size_t k=0; k<2; k++) {
369  for (size_t j=0; j<2; j++) {
370  gm.block(0, j*dim2, dim1, dim2) += W(k,j) * gmd[k];
371  }
372  }
373 
374  return gm;
375  }
376 
378 template<typename BasisType1, typename BasisType2>
379 Eigen::MatrixXd GramMatrix(
380  const Face & F,
381  const TangentFamily<BasisType1> & basis1,
382  const CurlBasis<BasisType2> & basis2,
383  MonomialFaceIntegralsType mono_int_map = {}
384  )
385  {
386  return GramMatrix(F, basis2, basis1, mono_int_map).transpose();
387  }
388 
389 
391 template<typename BasisType1, typename BasisType2>
392 typename boost::disable_if<boost::is_same<BasisType2, MonomialFaceIntegralsType>, Eigen::MatrixXd>::type GramMatrix(
393  const Face& F,
394  const DivergenceBasis<BasisType1> & basis1,
395  const BasisType2 & basis2,
396  MonomialFaceIntegralsType mono_int_map = {}
397  )
398  {
399  return GramMatrixDiv(F, basis1.ancestor(), basis2, mono_int_map);
400  }
401 
403 template<typename BasisType1, typename Basis2>
404 Eigen::MatrixXd GramMatrix(
405  const Face & F,
406  const BasisType1 & basis1,
407  const DivergenceBasis<Basis2> & basis2,
408  MonomialFaceIntegralsType mono_int_map = {}
409  )
410  {
411  return GramMatrixDiv(F, basis2.ancestor(), basis1, mono_int_map).transpose();
412  }
413 
415 /* This will work only if the generators of the TangentFamily are an orthonormal version of the Jacobian (change of variable 3D->2D) on the face */
416 template<typename BasisType1>
417 Eigen::MatrixXd GramMatrixDiv(
418  const Face & F,
419  const TangentFamily<BasisType1> & basis1,
420  const MonomialScalarBasisFace & basis2,
421  MonomialFaceIntegralsType mono_int_map = {}
422  )
423  {
424  size_t dim1 = basis1.dimension();
425  size_t dim2 = basis2.dimension();
426  Eigen::MatrixXd gm = Eigen::MatrixXd::Zero(dim1, dim2);
427 
428  // Integrals of monomials
429  size_t totaldegree = basis1.max_degree()+basis2.max_degree()-1;
430  MonomialFaceIntegralsType intmap = CheckIntegralsDegree(F, totaldegree, mono_int_map);
431 
432  for (size_t i = 0; i < 2; i++) {
433  gm.block(i*dim1/2, 0, dim1/2, dim2) = GMScalarDerivative(F, basis1.ancestor(), basis2, i, intmap);
434  }
435 
436  return gm/F.diam();
437  }
438 
440 Eigen::MatrixXd GramMatrixDiv(
441  const Face & F,
442  const RolyComplBasisFace & basis1,
443  const MonomialScalarBasisFace & basis2,
444  MonomialFaceIntegralsType mono_int_map = {}
445  );
446 
448 template<typename BasisType1, typename BasisType2>
449 Eigen::MatrixXd GramMatrixDiv(
450  const Face& F,
451  const BasisType1 & basis1,
452  const BasisType2 & basis2,
453  MonomialFaceIntegralsType mono_int_map = {}
454  )
455  {
456  // If no ancestor is to be used, we shouldn't be in this overload
457  static_assert(useAncestor<BasisType1>() || useAncestor<BasisType2>(), "No method to compute this Gram matrix");
458 
459  if constexpr (!useAncestor<BasisType1>() && useAncestor<BasisType2>()) {
460  return transformGM(basis2, 'C', GramMatrixDiv(F, basis1, basis2.ancestor(), mono_int_map) );
461  } else if constexpr (useAncestor<BasisType1>() && !useAncestor<BasisType2>()) {
462  return transformGM(basis1, 'R', GramMatrixDiv(F, basis1.ancestor(), basis2, mono_int_map) );
463  } else {
464  return transformGM(basis1, 'R', transformGM(basis2, 'C', GramMatrixDiv(F, basis1.ancestor(), basis2.ancestor(), mono_int_map) ) );
465  }
466  }
467 
468 
469 
470 
472 } // end of namespace HArDCore3D
473 
474 #endif // end of _GMPOLY_FACE_HPP
Basis for the space of curls of polynomials.
Definition: basis.hpp:1290
Basis (or rather family) of divergence of an existing basis.
Definition: basis.hpp:1353
Scalar monomial basis on a face.
Definition: basis.hpp:225
Basis for the complement R^{c,k}(F) in P^k(F)^2 of the range of the vectorial rotational on a face.
Definition: basis.hpp:1580
Vector family for polynomial functions that are tangent to a certain place (determined by the generat...
Definition: basis.hpp:920
Vector family obtained by tensorization of a scalar family.
Definition: basis.hpp:609
size_t dimension() const
Return the dimension of the family.
Definition: basis.hpp:956
size_t dimension() const
Return the dimension of the family.
Definition: basis.hpp:640
constexpr const ScalarFamilyType & ancestor() const
Return the ancestor (family that has been tensorized)
Definition: basis.hpp:747
constexpr const BasisType & ancestor() const
Return the ancestor (basis that the gradient was taken of)
Definition: basis.hpp:1335
size_t dimension() const
Dimension of the basis.
Definition: basis.hpp:253
constexpr const BasisType & ancestor() const
Return the ancestor (basis that the gradient was taken of)
Definition: basis.hpp:1398
constexpr const ScalarFamilyType & ancestor() const
Return the ancestor (family used for the tangent)
Definition: basis.hpp:982
const JacobianType & jacobian() const
Return the Jacobian of the coordinate system transformation.
Definition: basis.hpp:1620
Eigen::Matrix< double, 2, dimspace > generators() const
Returns the generators of the basis functions.
Definition: basis.hpp:994
size_t max_degree() const
Returns the maximum degree of the basis functions.
Definition: basis.hpp:271
size_t dimension() const
Dimension of the basis.
Definition: basis.hpp:1608
size_t max_degree() const
Returns the maximum degree of the basis functions.
Definition: basis.hpp:988
size_t max_degree() const
Returns the maximum degree of the basis functions.
Definition: basis.hpp:1626
size_t dimension() const
Compute the dimension of the basis.
Definition: basis.hpp:1323
Eigen::MatrixXd GramMatrix(const Cell &T, const MonomialScalarBasisCell &basis1, const MonomialScalarBasisCell &basis2, MonomialCellIntegralsType mono_int_map={})
Computes the Gram Matrix of a pair of local scalar monomial bases.
Definition: GMpoly_cell.cpp:170
MonomialFaceIntegralsType IntegrateFaceMonomials(const Face &F, const int maxdeg)
Compute all integrals on a face of face monomials up to a total degree.
Definition: GMpoly_face.cpp:67
Eigen::MatrixXd GramMatrixDiv(const Cell &T, const TensorizedVectorFamily< BasisType1, N > &basis1, const MonomialScalarBasisCell &basis2, MonomialCellIntegralsType mono_int_map={})
Template to compute the Gram Matrix of a Divergence<Tensorized> basis and a monomial scalar basis.
Definition: GMpoly_cell.hpp:903
std::unordered_map< Eigen::Vector2i, double, VecFaceHash > MonomialFaceIntegralsType
Type for list of face integrals of monomials.
Definition: GMpoly_face.hpp:51
Eigen::MatrixXd GMScalarDerivative(const Cell &T, const MonomialScalarBasisCell &basis1, const MonomialScalarBasisCell &basis2, const size_t m, MonomialCellIntegralsType mono_int_map={})
Computes the Gram Matrix of a pair of local scalar monomial bases, taking a partial derivative of the...
Definition: GMpoly_cell.cpp:244
MonomialCellIntegralsType CheckIntegralsDegree(const Cell &T, const size_t degree, const MonomialCellIntegralsType &mono_int_map={})
Checks if the degree of an existing list of monomial integrals is sufficient, other re-compute and re...
Definition: GMpoly_cell.cpp:160
size_t operator()(const Eigen::Vector2i &p) const
Definition: GMpoly_face.hpp:43
Eigen::MatrixXd GMRolyComplScalar(const Cell &T, const RolyComplBasisCell &rolycompl_basis, const MonomialScalarBasisCell &mono_basis, const size_t m, MonomialCellIntegralsType mono_int_map={})
Computes the Gram Matrix of the mth component of a RolyCompl Basis and a monomial basis.
Definition: GMpoly_cell.cpp:298
Eigen::MatrixXd transformGM(const Family< BasisType > &family_basis, const char RC, const Eigen::MatrixXd &anc_GM)
Transforms a Gram Matrix from an ancestor to a family basis.
Definition: GMpoly_cell.hpp:85
std::vector< MonomialFaceIntegralsType > IntegrateFaceMonomials_onEdges(const Face &F, const size_t maxdeg)
Compute all integrals, on the edges of a face, of the face monomials up to a total degree.
Definition: GMpoly_face.cpp:6
Definition: ddr-magnetostatics.hpp:40
MeshND::VectorRd< 2 > VectorRd
Definition: Mesh2D.hpp:14
MeshND::Face< 2 > Face
Definition: Mesh2D.hpp:12
Hash function for VectorZd type.
Definition: GMpoly_face.hpp:42