HArD::Core3D
Hybrid Arbitrary Degree::Core 3D - Library to implement 3D schemes with vertex, edge, face and cell polynomials as unknowns
hybridcore.hpp
Go to the documentation of this file.
1 // Data structures and methods to implement hybrid schemes in 3D, with polynomial unknowns
2 // in the cells and on the faces (and also edges), such as Hybrid High-order (HHO) schemes.
3 //
4 //
5 // Author: Jerome Droniou (jerome.droniou@monash.edu)
6 //
7 
8 /*
9  *
10  * This library was developed around HHO methods, although some parts of it have a more
11  * general purpose. If you use this code or part of it in a scientific publication,
12  * please mention the following book as a reference for the underlying principles
13  * of HHO schemes:
14  *
15  * The Hybrid High-Order Method for Polytopal Meshes: Design, Analysis, and Applications.
16  * D. A. Di Pietro and J. Droniou. Modeling, Simulation and Applications, vol. 19.
17  * Springer International Publishing, 2020, xxxi + 525p. doi: 10.1007/978-3-030-37203-3.
18  * url: https://hal.archives-ouvertes.fr/hal-02151813.
19  *
20  */
21 
22 #ifndef HYBRIDCORE_HPP
23 #define HYBRIDCORE_HPP
24 
25 #include <cassert>
26 #include <cmath>
27 
28 #include <functional>
29 #include <memory>
30 #include <string>
31 #include <vector>
32 #include <mesh.hpp>
33 #include <quadraturerule.hpp>
34 #include <basis.hpp>
35 #include <iostream>
36 #include <parallel_for.hpp>
37 
43 namespace HArDCore3D {
44 
45 
51  // -----------------------------------------
52  // Free Functions
53  // -----------------------------------------
54 
55  // Dimension of polynomial spaces -- only specialisations are relevant
56  template<typename GeometricSupport>
57  inline size_t const DimPoly(int m);
58 
60  template<>
61  inline const size_t DimPoly<Cell>(const int m)
62  {
63  return (m >= 0 ? (m * (m + 1) * (2 * m + 1) + 9 * m * (m + 1) + 12 * (m + 1)) / 12 : 0);
64  }
65 
67  template<>
68  inline const size_t DimPoly<Face>(const int m)
69  {
70  return (m >= 0 ? (m + 1) * (m + 2) / 2 : 0);
71  }
72 
74  template<>
75  inline const size_t DimPoly<Edge>(const int m)
76  {
77  return (m >= 0 ? m + 1 : 0);
78  }
79 
80  //-----------------------------------------------------------------------------
81  // UVector class definition
82  //-----------------------------------------------------------------------------
86  class UVector
87  {
88  public:
89  UVector(
90  const Eigen::VectorXd values,
91  const Mesh& mesh,
92  const int cell_deg,
93  const size_t face_deg
94  );
95 
97  inline Eigen::VectorXd & asVectorXd() const {
98  return m_values;
99  }
100 
102  inline const int get_cell_deg() const{
103  return m_cell_deg;
104  }
105 
107  inline const size_t get_face_deg() const{
108  return m_face_deg;
109  }
110 
112  inline const size_t n_cell_dofs() const{
113  return DimPoly<Cell>( std::max(m_cell_deg,0) );
114  }
115 
117  inline const size_t n_face_dofs() const{
118  return DimPoly<Face>( m_face_deg );
119  }
120 
122  inline const size_t n_total_cell_dofs() const{
123  return m_mesh.n_cells() * n_cell_dofs();
124  }
125 
127  Eigen::VectorXd restr(size_t iT) const;
128 
131  assert(m_cell_deg == b.get_cell_deg() || m_face_deg == b.get_face_deg() );
132  return UVector(m_values + b.asVectorXd(), m_mesh, m_cell_deg, m_face_deg);
133  }
134 
137  assert(m_cell_deg == b.get_cell_deg() || m_face_deg == b.get_face_deg() );
138  return UVector(m_values - b.asVectorXd(), m_mesh, m_cell_deg, m_face_deg);
139  }
140 
142  double operator()(size_t index) const{
143  return m_values(index);
144  }
145 
146  private:
147  mutable Eigen::VectorXd m_values;
148  const Mesh& m_mesh;
149  const int m_cell_deg;
150  const size_t m_face_deg;
151 
152  };
153 
154 
155  // ----------------------------------------------------------------------------
156  // HybridCore class definition
157  // ----------------------------------------------------------------------------
158 
173  class HybridCore
174  {
175 
176  public:
178 
181  HybridCore(
182  const Mesh* mesh_ptr,
183  const int cell_deg,
184  const size_t face_deg,
185  const int edge_deg,
186  const bool use_threads = true,
187  std::ostream & output = std::cout,
188  const bool ortho = true
189  );
190 
191  //---- Basis functions types -----//
195 
196  //-------- Getters --------//
198  inline const Mesh* get_mesh() const {return m_mesh;}
199 
201  inline const int CellDegree() const { return m_cell_deg; };
202  inline const int CellDegreePos() const { return m_cell_deg_pos; };
204  inline const size_t FaceDegree() const { return m_face_deg; };
205 
207  inline const PolyCellBasisType & CellBasis(size_t iT) const
208  {
209  // Make sure that the basis has been created
210  assert( m_cell_basis[iT] );
211  return *m_cell_basis[iT].get();
212  }
213 
215  inline const PolyFaceBasisType & FaceBasis(size_t iF) const
216  {
217  // Make sure that the basis has been created
218  assert( m_face_basis[iF] );
219  return *m_face_basis[iF].get();
220  }
221 
223  inline const PolyEdgeBasisType & EdgeBasis(size_t iE) const
224  {
225  // Make sure that the basis has been created
226  assert( m_edge_basis[iE] );
227  return *m_edge_basis[iE].get();
228  }
229 
230  //-------- Functions ------------//
232  double L2norm(
233  const UVector &Xh
234  ) const;
235 
237  double H1norm(
238  const UVector &Xh
239  ) const;
240 
242  template<typename ContinuousFunction>
244  const ContinuousFunction& f,
245  const int deg_cell,
246  const size_t deg_face,
247  size_t doe
248  ) const;
251  Eigen::VectorXd compute_weights(size_t iT) const;
252 
254  double evaluate_in_cell(const UVector Xh, size_t iT, VectorRd x) const;
256  double evaluate_in_face(const UVector Xh, size_t iF, VectorRd x) const;
257 
259  Eigen::VectorXd VertexValues(
260  const UVector Xh,
261  const std::string from_dofs
262  );
263 
264  private:
265  // Mesh
266  const Mesh* m_mesh; // Pointer to mesh data
267  // Degree of the cell polynomials (can be -1).
268  const int m_cell_deg;
269  const size_t m_cell_deg_pos;
270  // Degree of the face polynomials
271  const int m_face_deg;
272  // Degree of the edge polynomials
273  const int m_edge_deg;
274  // Using threads
275  bool m_use_threads;
276  // Output stream
277  std::ostream & m_output;
278  // Orthonormalise or not the basis functions
279  bool m_ortho;
280 
281  // Cell, face and edges bases
282  std::vector<std::unique_ptr<PolyCellBasisType>> m_cell_basis;
283  std::vector<std::unique_ptr<PolyFaceBasisType>> m_face_basis;
284  std::vector<std::unique_ptr<PolyEdgeBasisType>> m_edge_basis;
285 
286  // Creates the cell, face and edge bases
287  PolyCellBasisType _construct_cell_basis(size_t iT);
288  PolyFaceBasisType _construct_face_basis(size_t iF);
289  PolyEdgeBasisType _construct_edge_basis(size_t iF);
290  };
291 
292 
293 
294  // -------------------------------------------------------------
295  // ------- Interpolates continuous function on discrete space
296 
297  template<typename ContinuousFunction>
298  UVector HybridCore::interpolate(const ContinuousFunction& f, int cell_deg, size_t face_deg, size_t doe) const {
299 
300  size_t cell_deg_pos = std::max(cell_deg, 0);
301  assert(cell_deg <= CellDegree() || face_deg <= FaceDegree() || cell_deg > -1);
302 
303  // Sizes of local interpolation
304  size_t n_cell_dofs = DimPoly<Cell>(cell_deg_pos);
305  size_t n_total_cell_dofs = m_mesh->n_cells() * n_cell_dofs;
306  size_t n_face_dofs = DimPoly<Face>(face_deg);
307  size_t n_total_face_dofs = m_mesh->n_faces() * n_face_dofs;
308  Eigen::VectorXd XTF = Eigen::VectorXd::Zero( n_total_cell_dofs + n_total_face_dofs );
309 
310  // Face projections
311  std::function<void(size_t, size_t)> construct_all_face_projections
312  = [&](size_t start, size_t end)->void
313  {
314  for (size_t iF = start; iF < end; iF++) {
315  Face F = *m_mesh->face(iF);
316 
317  // Compute the L2 projection on face
319  boost::multi_array<double, 2> phiF_quadF = evaluate_quad<Function>::compute(FaceBasis(iF), quadF);
320  Eigen::VectorXd UF = l2_projection<PolyFaceBasisType>(f, FaceBasis(iF), quadF, phiF_quadF);
321 
322  // Fill in the complete vector of DOFs
323  XTF.segment(n_total_cell_dofs + iF * n_face_dofs, n_face_dofs) = UF;
324  }
325  };
326  parallel_for(m_mesh->n_faces(), construct_all_face_projections, m_use_threads);
327 
328  // Cell projections
329  std::function<void(size_t, size_t)> construct_all_cell_projections
330  = [&](size_t start, size_t end)->void
331  {
332  for (size_t iT = start; iT < end; iT++) {
333  Cell* cell = m_mesh->cell(iT);
334 
335  // L2 projection in cell
336  // Mass matrix in cell
337  QuadratureRule quadT = generate_quadrature_rule(*cell, doe);
338  boost::multi_array<double, 2> phiT_quadT = evaluate_quad<Function>::compute(CellBasis(iT), quadT);
339  Eigen::MatrixXd MT = compute_gram_matrix(phiT_quadT, phiT_quadT, quadT, n_cell_dofs, n_cell_dofs, "sym");
340 
341  // Vector of integrals of f against basis functions
342  Eigen::VectorXd bT = Eigen::VectorXd::Zero(n_cell_dofs);
343  for (size_t i = 0; i < n_cell_dofs; i++) {
344  for (size_t iqn = 0; iqn < quadT.size(); iqn++){
345  bT(i) += quadT[iqn].w * phiT_quadT[i][iqn] * f(quadT[iqn].vector());
346  }
347  }
348 
349  // Vector of coefficients (on cell basis functions) of the L2(T) projection of f
350  Eigen::VectorXd UT = MT.ldlt().solve(bT);
351 
352  // Fill in the complete vector of DOFs
353  size_t offset_T = iT * n_cell_dofs;
354  XTF.segment(offset_T, n_cell_dofs) = UT;
355 
356  // Special case of L=-1, we replace the previously computed cell value with the proper average of face values
357  if ( cell_deg==-1 ){
358  size_t nfaces = cell->n_faces();
359  // Weights corresponding to the values in cells/on faces
360  Eigen::VectorXd barycoefT = compute_weights(iT);
361  // We transform these weights so that they apply to the coefficients on the basis functions
362  VectorRd xT = cell->center_mass();
363  double phiT_cst = CellBasis(iT).function(0, xT);
364  for (size_t ilF = 0; ilF < nfaces; ilF++){
365  VectorRd xF = cell->face(ilF)->center_mass();
366  size_t iF = cell->face(ilF)->global_index();
367  double phiF_cst = FaceBasis(iF).function(0, xF);
368  barycoefT(ilF) *= phiF_cst / phiT_cst;
369  }
370 
371  XTF(iT) = 0;
372  for (size_t ilF = 0; ilF < nfaces; ilF++) {
373  size_t iF = cell->face(ilF)->global_index();
374  XTF(iT) += barycoefT(ilF) * XTF(n_total_cell_dofs + iF);
375  }
376  }
377 
378  }
379  };
380  parallel_for(m_mesh->n_cells(), construct_all_cell_projections, m_use_threads);
381 
382  return UVector(XTF, *get_mesh(), cell_deg, face_deg);
383  }
384 
385 
386 
387  // --------------------------------------------------------------------------------------------------
388  // ------- Functions that return class elements
389 
390 
391 
393 
394 } // end of namespace HArDCore3D
395 
396 #endif /* HYBRIDCORE_HPP */
Family of functions expressed as linear combination of the functions of a given basis.
Definition: basis.hpp:388
Definition: hybridcore.hpp:174
Definition: hybridcore.hpp:87
Class to describe a mesh.
Definition: MeshND.hpp:17
static boost::multi_array< typename detail::basis_evaluation_traits< BasisType, BasisFunction >::ReturnValue, 2 > compute(const BasisType &basis, const QuadratureRule &quad)
Generic basis evaluation.
Definition: basis.hpp:2189
FunctionValue function(size_t i, const VectorRd &x) const
Evaluate the i-th function at point x.
Definition: basis.hpp:427
Eigen::MatrixXd compute_gram_matrix(const boost::multi_array< VectorRd, 2 > &B1, const boost::multi_array< double, 2 > &B2, const QuadratureRule &qr)
Compute the Gram-like matrix given a family of vector-valued and one of scalar-valued functions by te...
Definition: basis.cpp:339
static void parallel_for(unsigned nb_elements, std::function< void(size_t start, size_t end)> functor, bool use_threads=true)
Generic function to execute threaded processes.
Definition: parallel_for.hpp:58
bool use_threads
Definition: HHO_DiffAdvecReac.hpp:47
size_t const DimPoly(int m)
Eigen::VectorXd compute_weights(size_t iT) const
Computes the weights to get cell values from face values when l=-1.
Definition: hybridcore.cpp:175
double evaluate_in_face(const UVector Xh, size_t iF, VectorRd x) const
Evaluates a discrete function on the face iF at point x.
Definition: hybridcore.cpp:309
HybridCore(const Mesh *mesh_ptr, const int cell_deg, const size_t face_deg, const int edge_deg, const bool use_threads=true, std::ostream &output=std::cout, const bool ortho=true)
Class constructor: initialises the data structure with the given mesh, and desired polynomial degrees...
Definition: hybridcore.cpp:51
const size_t n_cell_dofs() const
Number of dofs in each cell.
Definition: hybridcore.hpp:112
const int CellDegree() const
Return the degree of cell polynomials.
Definition: hybridcore.hpp:201
Eigen::VectorXd VertexValues(const UVector Xh, const std::string from_dofs)
From a hybrid function, computes a vector of values at the vertices of the mesh.
Definition: hybridcore.cpp:325
const PolyEdgeBasisType & EdgeBasis(size_t iE) const
Return edge basis for edge with global index iE.
Definition: hybridcore.hpp:223
Eigen::VectorXd restr(size_t iT) const
Extract the restriction of the unknowns corresponding to cell iT and its faces.
Definition: hybridcore.cpp:28
const int CellDegreePos() const
Definition: hybridcore.hpp:202
const int get_cell_deg() const
Return the cell degree.
Definition: hybridcore.hpp:102
const size_t DimPoly< Face >(const int m)
Compute the size of the basis of 2-variate polynomials up to degree m.
Definition: hybridcore.hpp:68
const size_t n_total_cell_dofs() const
Total number of cell dofs (in the vector, this is where the face dofs start)
Definition: hybridcore.hpp:122
Family< MonomialScalarBasisCell > PolyCellBasisType
type for cell basis
Definition: hybridcore.hpp:192
const PolyFaceBasisType & FaceBasis(size_t iF) const
Return face basis for face with global index iF.
Definition: hybridcore.hpp:215
UVector operator+(const UVector &b)
Overloads the addition: adds the coefficients.
Definition: hybridcore.hpp:130
const size_t get_face_deg() const
Return the face degree.
Definition: hybridcore.hpp:107
double evaluate_in_cell(const UVector Xh, size_t iT, VectorRd x) const
Evaluates a discrete function in the cell iT at point x.
Definition: hybridcore.cpp:298
const size_t n_face_dofs() const
Number of dofs on each face.
Definition: hybridcore.hpp:117
Family< MonomialScalarBasisFace > PolyFaceBasisType
type for face basis
Definition: hybridcore.hpp:193
double L2norm(const UVector &Xh) const
Compute L2 norm of a discrete function (using cell values)
Definition: hybridcore.cpp:201
const size_t FaceDegree() const
Return the degree of face polynomials.
Definition: hybridcore.hpp:204
const size_t DimPoly< Cell >(const int m)
Compute the size of the basis of 3-variate polynomials up to degree m.
Definition: hybridcore.hpp:61
Eigen::VectorXd & asVectorXd() const
Return the values as an Eigen vector.
Definition: hybridcore.hpp:97
double operator()(size_t index) const
Overloads the (): returns the corresponding coefficient.
Definition: hybridcore.hpp:142
const size_t DimPoly< Edge >(const int m)
Compute the size of the basis of 1-variate polynomials up to degree m.
Definition: hybridcore.hpp:75
Family< MonomialScalarBasisEdge > PolyEdgeBasisType
type for edge basis
Definition: hybridcore.hpp:194
double H1norm(const UVector &Xh) const
Compute discrete H1 norm of a discrete function.
Definition: hybridcore.cpp:227
UVector interpolate(const ContinuousFunction &f, const int deg_cell, const size_t deg_face, size_t doe) const
Compute the interpolant in the discrete space of a continuous function.
Definition: hybridcore.hpp:298
UVector(const Eigen::VectorXd values, const Mesh &mesh, const int cell_deg, const size_t face_deg)
Definition: hybridcore.cpp:19
const Mesh * get_mesh() const
Returns a pointer to the mesh.
Definition: hybridcore.hpp:198
UVector operator-(const UVector &b)
Overloads the subtraction: subtracts the coefficients.
Definition: hybridcore.hpp:136
const PolyCellBasisType & CellBasis(size_t iT) const
Return cell basis for element with global index iT.
Definition: hybridcore.hpp:207
std::size_t n_faces() const
number of faces in the mesh.
Definition: MeshND.hpp:59
Face< dimension > * face(std::size_t index) const
get a constant pointer to a face using its global index
Definition: MeshND.hpp:196
std::size_t n_cells() const
number of cells in the mesh.
Definition: MeshND.hpp:60
Cell< dimension > * cell(std::size_t index) const
get a constant pointer to a cell using its global index
Definition: MeshND.hpp:197
QuadratureRule generate_quadrature_rule(const Cell &T, const int doe, const bool force_split)
Generate quadrature rule on mesh element.
Definition: quadraturerule.cpp:11
std::vector< QuadratureNode > QuadratureRule
Definition: quadraturerule.hpp:61
Definition: ddr-magnetostatics.hpp:40
MeshND::VectorRd< 2 > VectorRd
Definition: Mesh2D.hpp:14
MeshND::Face< 2 > Face
Definition: Mesh2D.hpp:12
MeshND::Cell< 2 > Cell
Definition: Mesh2D.hpp:13