HArD::Core3D
Hybrid Arbitrary Degree::Core 3D - Library to implement 3D schemes with vertex, edge, face and cell polynomials as unknowns
Loading...
Searching...
No Matches
MeshObject.hpp
Go to the documentation of this file.
1#include <array>
2#include <vector>
3#include <map>
4#include <iostream>
5#include <cmath>
6#include <Eigen/Dense>
7#include <math.hpp>
8#include <algorithm>
9// #include <Eigen/FullPivLU>
10
11#ifndef _MESHOBJECT_HPP
12#define _MESHOBJECT_HPP
13
14namespace MeshND
15{
16 template <size_t space_dim>
17 using VectorRd = Eigen::Matrix<double, space_dim, 1>;
18
19 template <size_t space_dim>
20 using VectorZd = Eigen::Matrix<int, space_dim, 1>;
21
22 template <size_t space_dim, size_t object_dim>
23 using Simplex = std::array<VectorRd<space_dim>, object_dim + 1>;
24
25 template <size_t space_dim, size_t object_dim>
26 using Simplices = std::vector<Simplex<space_dim, object_dim>>;
27
29 template <size_t space_dim, size_t object_dim>
31
33 template <size_t space_dim, size_t object_dim>
35
46 // ----------------------------------------------------------------------------
47 // MeshObject class definition
48 // ----------------------------------------------------------------------------
49
55 template <size_t space_dim, size_t object_dim>
57 {
58 public:
60 MeshObject(size_t index, Simplices<space_dim, object_dim> simplices);
61
63 MeshObject(size_t index, Simplex<space_dim, object_dim> simplex);
64
67
69 MeshObject();
70
73
74 // inline size_t dim() const { return object_dim; }
75
77 inline size_t global_index() const { return _index; }
79 inline double diam() const { return _diameter; }
81 inline VectorRd<space_dim> center_mass() const { return _center_mass; }
83 inline double measure() const { return _measure; }
84
86 inline Simplices<space_dim, object_dim> get_simplices() const { return _simplices; }
87 inline Simplices<space_dim, object_dim>& set_simplices() { return _simplices; }
89 inline void set_global_index(const size_t idx) { _index = idx; }
91 inline bool is_boundary() const { return _is_boundary; }
93 inline void set_boundary(bool val) { _is_boundary = val; }
95 inline bool is_flat() const { return _is_flat; }
96
98 inline std::vector<MeshObject<space_dim, 0>*> get_vertices() const { return _vertices; }
100 inline std::vector<MeshObject<space_dim, 1>*> get_edges() const { return _edges; }
102 inline std::vector<MeshObject<space_dim, space_dim - 1>*> get_faces() const { return _faces; }
104 inline std::vector<MeshObject<space_dim, space_dim>*> get_cells() const { return _cells; }
105
107 inline size_t n_vertices() const { return _vertices.size(); }
109 inline size_t n_edges() const { return _edges.size(); }
111 inline size_t n_faces() const { return _faces.size(); }
113 inline size_t n_cells() const { return _cells.size(); }
114
115 MeshObject<space_dim, 0>* vertex(const size_t i) const;
116 MeshObject<space_dim, 1>* edge(const size_t i) const;
117 MeshObject<space_dim, space_dim - 1>* face(const size_t i) const;
118 MeshObject<space_dim, space_dim>* cell(const size_t i) const;
119
124
126 int index_edge(const MeshObject<space_dim, 1>* edge) const;
129
131 void set_coords(const VectorRd<space_dim> & x);
132
133 VectorRd<space_dim> face_normal(const size_t face_index) const;
134 VectorRd<space_dim> edge_normal(const size_t edge_index) const;
135
136 int face_orientation(const size_t face_index) const;
137 int edge_orientation(const size_t edge_index) const;
138
139 int induced_orientation(const size_t index) const;
140
143 Eigen::Matrix<double,space_dim,2> face_tangent() const;
144
146
147 private:
148 size_t _index;
149 VectorRd<space_dim> _center_mass;
150 double _measure;
151 double _diameter;
152 bool _is_boundary;
153 bool _is_flat; // To record non-planar faces
155 VectorRd<space_dim> _normal; // uninitialised unless object_dim == space_dim - 1 (face)
156 std::vector<int> _face_directions; // empty unless object_dim == space_dim (cell)
157
158 std::vector<MeshObject<space_dim, 0>*> _vertices;
159 std::vector<MeshObject<space_dim, 1>*> _edges;
160 std::vector<MeshObject<space_dim, space_dim - 1>*> _faces;
161 std::vector<MeshObject<space_dim, space_dim>*> _cells;
162 };
163
165 template <size_t space_dim>
167
169 template <size_t space_dim>
171
173 template <size_t space_dim>
174 using Face = MeshObject<space_dim, space_dim - 1>;
175
177 template <size_t space_dim>
179
181
182 // -----------------------------------------------------------------
183 // ----------- Implementation of templated functions ---------------
184 // -----------------------------------------------------------------
185
186 template <size_t space_dim, size_t object_dim>
188 {
189 VectorRd<space_dim> center_mass = Eigen::VectorXd::Zero(space_dim);
190
191 for (auto& coord : simplex)
192 {
193 for (size_t i = 0; i < space_dim; ++i)
194 {
195 center_mass(i) += coord(i);
196 }
197 }
198 return center_mass / (object_dim + 1);
199 }
200
201 template <size_t space_dim, size_t object_dim>
203 {
204 Eigen::MatrixXd CM_mat = Eigen::MatrixXd::Zero(object_dim + 2, object_dim + 2);
205 for (size_t i = 0; i < object_dim + 1; ++i)
206 {
207 VectorRd<space_dim> i_coords = simplex[i];
208 for (size_t j = i + 1; j < object_dim + 1; ++j)
209 {
210 VectorRd<space_dim> j_coords = simplex[j];
211 double norm = (j_coords - i_coords).norm();
212 CM_mat(i, j) = norm * norm;
213 CM_mat(j, i) = CM_mat(i, j);
214 }
215 CM_mat(i, object_dim + 1) = 1;
216 CM_mat(object_dim + 1, i) = 1;
217 }
218
219 // Calculate Cayley-Menger determinant
220 double det = CM_mat.determinant();
221 double scaling = std::pow(Math::factorial(object_dim), 2) * std::pow(2, object_dim);
222
223 return std::sqrt(std::abs(det / scaling));
224 }
225
226 template <size_t space_dim, size_t object_dim>
228 : _index(index), _simplices(simplices)
229 {
230 assert(space_dim >= object_dim);
231 assert(space_dim >= 2);
232
233 if (object_dim == 0 || object_dim == 1)
234 {
235 assert(simplices.size() == 1);
236 }
237
238 _is_boundary = false;
239
240 _measure = 0.0;
241 _center_mass = Eigen::VectorXd::Zero(space_dim);
242 std::vector<VectorRd<space_dim>> vertex_coords;
243 for (auto& simplex : simplices)
244 {
245 // assert(simplex.size() == _dim + 1);
246 double tmp = simplex_measure<space_dim, object_dim>(simplex);
247 _measure += tmp;
248 _center_mass += tmp * simplex_center_mass<space_dim, object_dim>(simplex);
249 for (auto& coord : simplex)
250 {
251 if (std::find(vertex_coords.begin(), vertex_coords.end(), coord) == vertex_coords.end())
252 {
253 vertex_coords.push_back(coord); // if coord not already in vertex_coords, add it
254 }
255 }
256 }
257 _center_mass /= _measure;
258
259 _diameter = 0.0;
260 for (auto it = vertex_coords.begin(); it != vertex_coords.end(); ++it)
261 {
262 for (auto jt = it; jt != vertex_coords.end(); ++jt)
263 {
264 _diameter = std::max(_diameter, (*it - *jt).norm()); // probably more efficient methods
265 }
266 }
267
268 _is_flat = true;
269
270 if (object_dim == space_dim - 1) // find the normal to the face and check if it is flat
271 {
272 // We compute the normal using the most perpendicular pair of vectors created from the center to any vertex
273 // Find all points in the face that are not the center of mass
274 std::vector<VectorRd<space_dim>> points_in_face;
275 for (size_t i = 0; i < _simplices.size(); ++i)
276 {
277 for (size_t j = 0; j < space_dim; ++j)
278 {
279 if( (std::find(points_in_face.begin(), points_in_face.end(), _simplices[i][j]) == points_in_face.end()) && ( (_simplices[i][j]-_center_mass).norm()>1e-8 * _diameter) )
280 {
281 points_in_face.push_back(_simplices[i][j]);
282 }
283 }
284 }
285
287 double norm_perp_vec = 0.;
288 for (size_t iV = 0 ; iV < points_in_face.size(); iV++){
289 VectorRd<space_dim> t1 = (points_in_face[iV] - _center_mass).normalized();
290 for (size_t iVp = iV+1; iVp < points_in_face.size(); iVp++){
291 VectorRd<space_dim> t2 = (points_in_face[iVp] - _center_mass).normalized();
292 VectorRd<space_dim> tmp = t1.cross(t2);
293 double norm_tmp = tmp.norm();
294 if (norm_tmp > norm_perp_vec){
295 perp_vec = tmp;
296 norm_perp_vec = norm_tmp;
297 }
298 }
299 }
300 _normal = perp_vec / norm_perp_vec;
301
302 // Checking that the face is planar: all points_in_face should lie in the plane orthogonal to _normal at the center of mass
303 for (size_t iV = 0; iV < points_in_face.size(); iV++){
304 VectorRd<space_dim> v_xF = points_in_face[iV]-_center_mass;
305 if (std::abs( v_xF.dot(_normal) ) > 1e-8 * v_xF.norm()){
306 _is_flat = false;
307 }
308 }
309
310 }
311 }
312
313 template <size_t space_dim, size_t object_dim>
315 : MeshObject(index, Simplices<space_dim, object_dim>(1, simplex))
316 {
317 }
318
319 template <size_t space_dim, size_t object_dim>
321 : MeshObject(index, Simplex<space_dim, object_dim>({ vertex }))
322 {
323 assert(object_dim == 0);
324 }
325
326 template <size_t space_dim, size_t object_dim>
328
329 template <size_t space_dim, size_t object_dim>
331
332 template <size_t space_dim, size_t object_dim>
334 {
335 assert(std::find(_vertices.begin(), _vertices.end(), vertex) == _vertices.end());
336 _vertices.push_back(vertex);
337 }
338
339 template <size_t space_dim, size_t object_dim>
341 {
342 assert(std::find(_edges.begin(), _edges.end(), edge) == _edges.end());
343 _edges.push_back(edge);
344 if (space_dim == 2)
345 {
346 assert(std::find(_faces.begin(), _faces.end(), reinterpret_cast<MeshObject<space_dim, space_dim - 1> *>(edge)) == _faces.end());
347 _faces.push_back(reinterpret_cast<MeshObject<space_dim, space_dim - 1> *>(edge));
348 }
349 }
350
351 template <size_t space_dim, size_t object_dim>
353 {
354 assert(std::find(_faces.begin(), _faces.end(), face) == _faces.end());
355 _faces.push_back(face);
356 if (space_dim == 2)
357 {
358 assert(std::find(_edges.begin(), _edges.end(), reinterpret_cast<MeshObject<space_dim, 1> *>(face)) == _edges.end());
359 _edges.push_back(reinterpret_cast<MeshObject<space_dim, 1> *>(face));
360 }
361 }
362
363 template <size_t space_dim, size_t object_dim>
365 {
366 assert(std::find(_cells.begin(), _cells.end(), cell) == _cells.end());
367 _cells.push_back(cell);
368 }
369
370 template <size_t space_dim, size_t object_dim>
372 {
373 assert(i < _vertices.size());
374 return _vertices[i];
375 }
376
377 template <size_t space_dim, size_t object_dim>
379 {
380 assert(i < _edges.size());
381 return _edges[i];
382 }
383
384 template <size_t space_dim, size_t object_dim>
385 MeshObject<space_dim, space_dim - 1>* MeshObject<space_dim, object_dim>::face(const size_t i) const
386 {
387 assert(i < _faces.size());
388 return _faces[i];
389 }
390
391 template <size_t space_dim, size_t object_dim>
393 {
394 assert(i < _cells.size());
395 return _cells[i];
396 }
397
398 template <size_t space_dim, size_t object_dim>
399 void MeshObject<space_dim, object_dim>::construct_face_orientations() // not very efficient - probably room for improvement
400 {
401 assert(object_dim == space_dim);
402 for (size_t iF = 0; iF < _faces.size(); ++iF)
403 {
404 VectorRd<space_dim> normal = _faces[iF]->normal();
405 Simplex<space_dim, object_dim - 1> face_simplex = _faces[iF]->get_simplices()[0];
406 VectorRd<space_dim> center = Eigen::VectorXd::Zero(space_dim);
407 double count;
408 for (auto& cell_simplex : this->get_simplices())
409 {
410 count = 0;
411 for (size_t i = 0; (i < cell_simplex.size()) && count < 2; ++i)
412 {
413 if (std::find(face_simplex.begin(), face_simplex.end(), cell_simplex[i]) == face_simplex.end())
414 {
415 ++count;
416 }
417 }
418 if (count == 1) // only don't share one coordinate
419 {
420 center = simplex_center_mass<space_dim, object_dim>(cell_simplex);
421 break;
422 }
423 }
424 assert(count == 1);
425 // _face_directions.push_back(Math::sgn((_faces[iF]->center_mass() - _center_mass).dot(normal))); // star shaped wrt center mass
426 _face_directions.push_back(Math::sgn((_faces[iF]->center_mass() - center).dot(normal)));
427 assert(_face_directions[iF] != 0);
428 }
429 }
430
431 template <size_t space_dim, size_t object_dim>
433 {
434 assert(object_dim == space_dim);
435 assert(face_index < _faces.size());
436 return _face_directions[face_index] * _faces[face_index]->normal();
437 }
438
439 template <size_t space_dim, size_t object_dim>
441 {
442 assert(object_dim == 2);
443 if (space_dim == 2)
444 {
445 return this->face_normal(edge_index);
446 }
447 if (space_dim == 3)
448 {
449 VectorRd<space_dim> edge_normal = _normal.cross(_edges[edge_index]->tangent()); // unit vector as normal and tangent are orthogonal unit vectors
450 return edge_normal;
451 }
452 }
453
454 template <size_t space_dim, size_t object_dim>
456 {
457 assert(object_dim == 0);
458 return this->get_simplices()[0][0];
459 }
460
461 template <size_t space_dim, size_t object_dim>
463 {
464 assert(object_dim == 0);
465 this->set_simplices()[0][0] = x;
466 }
467
468 template <size_t space_dim, size_t object_dim>
470 {
471 assert(object_dim == space_dim - 1);
472 return _normal;
473 }
474
475 template <size_t space_dim, size_t object_dim>
477 {
478 assert(object_dim == 1);
479 return (this->get_vertices()[1]->coords() - this->get_vertices()[0]->coords()).normalized();
480 }
481
482 template <size_t space_dim, size_t object_dim>
483 Eigen::Matrix<double,space_dim,2> MeshObject<space_dim, object_dim>::face_tangent() const
484 {
485 assert(object_dim == 2);
486 Eigen::Matrix<double,space_dim,2> rv;
487 rv.col(0) = edge(0)->tangent();
488 rv.col(1) = edge_normal(0);
489 return rv;
490 }
491
492 template <size_t space_dim, size_t object_dim>
494 {
495 auto itr = std::find(_vertices.begin(), _vertices.end(), vertex);
496 if (itr != _vertices.end())
497 {
498 return itr - _vertices.begin();
499 }
500 else
501 {
502 throw "Vertex not found";
503 }
504 }
505
506 template <size_t space_dim, size_t object_dim>
508 {
509 auto itr = std::find(_edges.begin(), _edges.end(), edge);
510 if (itr != _edges.end())
511 {
512 return itr - _edges.begin();
513 }
514 else
515 {
516 throw "Edge not found";
517 }
518 }
519
520 template <size_t space_dim, size_t object_dim>
522 {
523 auto itr = std::find(_faces.begin(), _faces.end(), face);
524 if (itr != _faces.end())
525 {
526 return itr - _faces.begin();
527 }
528 else
529 {
530 throw "Face not found";
531 }
532 }
533
534 template <size_t space_dim, size_t object_dim>
536 {
537 auto itr = std::find(_cells.begin(), _cells.end(), cell);
538 if (itr != _cells.end())
539 {
540 return itr - _cells.begin();
541 }
542 else
543 {
544 throw "Cell not found";
545 }
546 }
547 template <size_t space_dim, size_t object_dim>
549 {
550 assert(object_dim == space_dim);
551 assert(face_index < _faces.size());
552 return _face_directions[face_index];
553 }
554 template <size_t space_dim, size_t object_dim>
556 {
557 assert(object_dim == 2);
558 assert(edge_index < _edges.size());
559 return Math::sgn((_edges[edge_index]->center_mass() - this->center_mass()).dot(this->edge_normal(edge_index))); // assuming face is star-shaped wrt face-center !!
560 }
561 template <size_t space_dim, size_t object_dim>
563 {
564 assert((object_dim == 2 && index < _edges.size())||(object_dim == 3 && index < _faces.size()));
565 if constexpr(object_dim == 2) {
566 VectorRd<space_dim> const n = edge_orientation(index)*edge_normal(index),
567 t = edge(index)->tangent();
568 Eigen::Matrix<double,space_dim,2> const ab = face_tangent();
569 return Math::sgn(ab.col(0).dot(n)*ab.col(1).dot(t) - ab.col(0).dot(t)*ab.col(1).dot(n));
570 // If vol_f = da^db, vol_E = dt and n is the outward unit vector
571 // then da^db = (da(n)*db(t) - da(t)*db(n))dn^dt, hence i_{n}(da^db) = (da(n)*db(t) - da(t)*db(n))dn^dt
572 // The induced orientation on E is then sgn(da(n)*db(t) - da(t)*db(n)) dt
573 // sgn(da(n)*db(t) - da(t)*db(n)) should be equal to da(n)*db(t) - da(t)*db(n)
574 } else { // object_dim == 3
575 Eigen::Matrix<double,space_dim,object_dim> nab;
576 nab.rightCols(2) = face(index)->face_tangent();
577 nab.leftCols(1) = face_normal(index); // This seems inconsistent with the behavior in 2D, why does this one is outer and not edge_orientation?
578 return Math::sgn(nab.determinant());
579 // We assume that the volume form on T is dx^dy^dz, then dx^dy^dz = det(n,a,b) dn^da^db
580 // The induced orientation on F is then sign(det(n,a,b))
581 }
582 }
583
584} // namespace MeshND
585
586#endif
Generic class to describe a cell, face, edge or vertex.
Definition MeshObject.hpp:57
std::vector< MeshObject< space_dim, 0 > * > get_vertices() const
Returns the vertices of the MeshObject.
Definition MeshObject.hpp:98
int index_edge(const MeshObject< space_dim, 1 > *edge) const
Returns the local index of an edge.
Definition MeshObject.hpp:507
~MeshObject()
Destructor.
Definition MeshObject.hpp:330
double simplex_measure(Simplex< space_dim, object_dim > simplex)
Method to find the Lebesgue measure of an arbitrary simplex in arbitrary space.
Definition MeshObject.hpp:202
int face_orientation(const size_t face_index) const
Return the orientation of a Face.
Definition MeshObject.hpp:548
void add_face(MeshObject< space_dim, space_dim - 1 > *face)
Add a face to the MeshObject.
Definition MeshObject.hpp:352
int edge_orientation(const size_t edge_index) const
Return the orientation of a Edge (multiplied by edge_normal, gives the outer normal to the face)
Definition MeshObject.hpp:555
size_t n_vertices() const
Returns the number of vertices of the MeshObject.
Definition MeshObject.hpp:107
Simplices< space_dim, object_dim > & set_simplices()
Definition MeshObject.hpp:87
VectorRd< space_dim > simplex_center_mass(Simplex< space_dim, object_dim > simplex)
Method to find the center mass of an arbitrary simplex in arbitrary space.
Definition MeshObject.hpp:187
MeshObject< space_dim, space_dim - 1 > * face(const size_t i) const
Returns the i-th face of the MeshObject.
Definition MeshObject.hpp:385
size_t n_cells() const
Returns the number of cells of the MeshObject.
Definition MeshObject.hpp:113
MeshObject< space_dim, space_dim > * cell(const size_t i) const
Returns the i-th cell of the MeshObject.
Definition MeshObject.hpp:392
VectorRd< space_dim > face_normal(const size_t face_index) const
Return the outer normal of a Cell towards the Face located at face_index.
Definition MeshObject.hpp:432
double diam() const
Returns the diameter of the MeshObject.
Definition MeshObject.hpp:79
VectorRd< space_dim > center_mass() const
Returns the center mass of the MeshObject.
Definition MeshObject.hpp:81
VectorRd< space_dim > coords() const
Return the coordinates of a Vertex.
Definition MeshObject.hpp:455
int induced_orientation(const size_t index) const
Return 1 if the volume form on the boundary is positively oriented, -1 else.
Definition MeshObject.hpp:562
void add_edge(MeshObject< space_dim, 1 > *edge)
Add an edge to the MeshObject.
Definition MeshObject.hpp:340
Eigen::Matrix< double, space_dim, 2 > face_tangent() const
Return the tangent space of a Face.
Definition MeshObject.hpp:483
double measure() const
Definition MeshObject.hpp:83
size_t global_index() const
Returns the global index of the MeshObject.
Definition MeshObject.hpp:77
void set_boundary(bool val)
Set the boundary value of the MeshObject.
Definition MeshObject.hpp:93
void set_coords(const VectorRd< space_dim > &x)
Set the coordinates of a Vertex.
Definition MeshObject.hpp:462
MeshObject< space_dim, 1 > * edge(const size_t i) const
Returns the i-th edge of the MeshObject.
Definition MeshObject.hpp:378
size_t n_faces() const
Returns the number of faces of the MeshObject.
Definition MeshObject.hpp:111
int index_face(const MeshObject< space_dim, space_dim - 1 > *face) const
Returns the local index of a face.
Definition MeshObject.hpp:521
void add_vertex(MeshObject< space_dim, 0 > *vertex)
Add a vertex to the MeshObject.
Definition MeshObject.hpp:333
bool is_boundary() const
Returns true if MeshObject is a boundary object, false otherwise.
Definition MeshObject.hpp:91
size_t n_edges() const
Returns the number of edges of the MeshObject.
Definition MeshObject.hpp:109
std::vector< MeshObject< space_dim, 1 > * > get_edges() const
Returns the edges of the MeshObject.
Definition MeshObject.hpp:100
MeshObject()
Null constructor.
Definition MeshObject.hpp:327
MeshObject< space_dim, 0 > * vertex(const size_t i) const
Returns the i-th vertex of the MeshObject.
Definition MeshObject.hpp:371
int index_cell(const MeshObject< space_dim, space_dim > *cell) const
Returns the local index of a cell.
Definition MeshObject.hpp:535
void set_global_index(const size_t idx)
Set the global index.
Definition MeshObject.hpp:89
Simplices< space_dim, object_dim > get_simplices() const
Returns the simplices making up the MeshObject.
Definition MeshObject.hpp:86
VectorRd< space_dim > normal() const
Return the normal of a Face.
Definition MeshObject.hpp:469
bool is_flat() const
Returns true if MeshObject is flat (only relevant for faces), false otherwise.
Definition MeshObject.hpp:95
VectorRd< space_dim > edge_normal(const size_t edge_index) const
Return the edge normal of a 2D object.
Definition MeshObject.hpp:440
VectorRd< space_dim > tangent() const
Return the tangent of a Edge.
Definition MeshObject.hpp:476
std::vector< MeshObject< space_dim, space_dim - 1 > * > get_faces() const
Returns the faces of the MeshObject.
Definition MeshObject.hpp:102
std::vector< MeshObject< space_dim, space_dim > * > get_cells() const
Return the cells of the MeshObject.
Definition MeshObject.hpp:104
void add_cell(MeshObject< space_dim, space_dim > *cell)
Add a cell to the MeshObject.
Definition MeshObject.hpp:364
void construct_face_orientations()
Set the directions of the face normals of a cell.
Definition MeshObject.hpp:399
int index_vertex(const MeshObject< space_dim, 0 > *vertex) const
Returns the local index of a vertex.
Definition MeshObject.hpp:493
const int sgn(T val)
Definition math.hpp:41
const size_t factorial(size_t n)
Definition math.hpp:11
Definition MeshND.hpp:13
Eigen::Matrix< double, space_dim, 1 > VectorRd
Definition MeshObject.hpp:17
Eigen::Matrix< int, space_dim, 1 > VectorZd
Definition MeshObject.hpp:20
std::vector< Simplex< space_dim, object_dim > > Simplices
Definition MeshObject.hpp:26
std::array< VectorRd< space_dim >, object_dim+1 > Simplex
Definition MeshObject.hpp:23