LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
Loading...
Searching...
No Matches
check_mesh_completeness.cc
1#include "check_mesh_completeness.h"
2
3#include <gtest/gtest.h>
4#include <lf/mesh/mesh.h>
5#include <spdlog/fmt/ostr.h>
6#include <spdlog/spdlog.h>
7
8#include <iostream>
9
10#include "lf/mesh/hybrid2d/mesh.h"
11
12namespace lf::mesh::test_utils {
13bool checkMeshCompleteness(const Mesh& mesh) {
14 bool status = true; // Test passed or not ?
15 using size_type = Mesh::size_type; // type for indices
16 using dim_t = lf::base::RefEl::dim_t; // type for dimensions
17 // Obtain topological dimension of the mesh
18 const dim_t dim_mesh = mesh.DimMesh();
19 // Now run over all entities of co-dimension < dim_mesh
20 for (size_type co_dim = 0; co_dim < dim_mesh; ++co_dim) {
21 // Count occurrences of sub-entities of relative co-dimension 1
22 // To that end allocate a vector of counters
23 std::vector<size_type> entity_link_cnt(mesh.NumEntities(co_dim + 1), 0);
24
25 // Diagnostic output
26 // std::cout << "co-dim " << co_dim + 1 << ": " << mesh.Size(co_dim + 1)
27 // << " entities" << std::endl;
28
29 // Traverse all entities of a given co-dimension
30 for (const Entity* e : mesh.Entities(co_dim)) {
31 // Diagnostic output
32 // std::cout << "Entity(" << mesh.Index(e) << "): " << std::flush;
33
34 // Fetch subentities of co-dimension 1
35 auto sub_ent_range = e->SubEntities(1);
36 for (const Entity* sub_ent : sub_ent_range) {
37 // Diagnostic output
38 // std::cout << mesh.Index(sub_ent) << " " << std::flush;
39 // Obtain index of the sub-entity to address counter
40 entity_link_cnt[mesh.Index(*sub_ent)]++;
41 }
42 // For diagnostic output
43 // std::cout << std::endl;
44 } // end loop over entities
45
46 // Diagnostic output
47 // for(int j=0; j < entity_link_cnt.size() ; j++)
48 // std::cout << "Entity " << j << " -> " << entity_link_cnt[j] << " links"
49 // << std::endl;
50
51 // Maximal number of occurrences of a subentity, this many bins for counting
52 size_type max_subent_cnt =
53 *std::max_element(entity_link_cnt.begin(), entity_link_cnt.end());
54 // for (size_type cnt : entity_link_cnt) {
55 // if (cnt > max_subent_cnt) max_subent_cnt = cnt;
56 // }
57 std::vector<size_type> occurrence_cnt(max_subent_cnt + 1, 0);
58 size_type entity_index = 0;
59 for (size_type i : entity_link_cnt) {
60 occurrence_cnt[i]++;
61 EXPECT_GT(i, 0) << "Entity " << entity_index << ", co-dimension "
62 << co_dim + 1 << "not linked";
63 if (i == 0) {
64 status = false;
65 }
66 entity_index++;
67 }
68 // Output of diagnostic information
69 // Should depend on some control variable
70 std::cout << "Enties of dimension " << dim_mesh - co_dim - 1 << ": "
71 << std::endl;
72 for (int l = 0; l <= max_subent_cnt; l++) {
73 std::cout << l << " times linked: " << occurrence_cnt[l] << " entities"
74 << std::endl;
75 }
76 } // end loop over co-dimensions
77 return status;
78} // end checkMeshCompleteness
79
80std::shared_ptr<spdlog::logger>& WatertightLogger() {
81 static auto logger =
82 base::InitLogger("lf::mesh::test_utils::WatertightLogger");
83 return logger;
84}
85
86std::vector<std::pair<lf::base::RefEl, base::glb_idx_t>> isWatertightMesh(
87 const Mesh& mesh, bool vertices_only) {
88 base::dim_t dim_mesh = mesh.DimMesh();
89 std::vector<std::pair<lf::base::RefEl, base::glb_idx_t>> ret_vals{};
90
91 // "Reference coordinates" for a point: dummy argument
92 Eigen::Matrix<double, 0, 1> pt_ref_coord;
93
94 // Loop over cells and edges
95 for (int co_dim = dim_mesh; co_dim > 0; co_dim--) {
96 base::dim_t codim_pt = dim_mesh - co_dim; // co-dim of vertices
97 // Loop over entities of the specified co-dimension
98 for (const Entity* e : mesh.Entities(co_dim)) {
99 const lf::base::RefEl e_refel = e->RefEl();
100 const Eigen::MatrixXd& ref_el_corners(e_refel.NodeCoords());
101 const Eigen::MatrixXd vertex_coords(
102 e->Geometry()->Global(ref_el_corners));
103 const double approx_area =
104 (e->Geometry()->IntegrationElement(ref_el_corners))[0];
105 // Visit all nodes
106 auto sub_ents = e->SubEntities(codim_pt);
107 for (base::sub_idx_t j = 0; j < e_refel.NumNodes(); ++j) {
108 const Eigen::VectorXd node_coords(
109 sub_ents[j]->Geometry()->Global(pt_ref_coord));
110 // Check agreement of coordinates up to roundoff
111 if ((vertex_coords.col(j) - node_coords).squaredNorm() >
112 1.0E-8 * approx_area) {
113 ret_vals.emplace_back(e_refel, mesh.Index(*e));
114
115 SPDLOG_LOGGER_TRACE(WatertightLogger(),
116 "Node {} of {} ({}): position mismatch", j,
117 e_refel, mesh.Index(*e));
118
119 } // end geometry test
120 } // end loop over nodes
121 } // end loop over entities
122 } // end loop over co-dimensions
123 if (!vertices_only) {
124 // Check whether geometry of edges and cells match
125 // ASSERT_MSG(false,
126 // "Geometric compatibility test for edges and cells not yet
127 // implemented");
128 }
129
130 return ret_vals;
131} // namespace lf::mesh::test_utils
132
133} // namespace lf::mesh::test_utils
Represents a reference element with all its properties.
Definition ref_el.h:109
constexpr RefEl(RefElType type) noexcept
Create a RefEl from a lf::base::RefElType enum.
Definition ref_el.h:175
unsigned int dim_t
Definition ref_el.h:132
const Eigen::MatrixXd & NodeCoords() const
Get the coordinates of the nodes of this reference element.
Definition ref_el.h:241
constexpr size_type NumNodes() const
The number of nodes of this reference element.
Definition ref_el.h:213
Interface class representing a topological entity in a cellular complex
Definition entity.h:42
Abstract interface for objects representing a single mesh.
lf::base::size_type size_type
virtual std::span< const Entity *const > Entities(unsigned codim) const =0
All entities of a given codimension.
virtual size_type NumEntities(unsigned codim) const =0
The number of Entities that have the given codimension.
virtual unsigned DimMesh() const =0
The dimension of the manifold described by the mesh, or equivalently the maximum dimension of the ref...
virtual size_type Index(const Entity &e) const =0
Acess to the index of a mesh entity of any co-dimension.
unsigned int sub_idx_t
type for local indices of sub-entities
Definition types.h:28
unsigned int dim_t
type for dimensions and co-dimensions and numbers derived from them
Definition types.h:32
std::shared_ptr< spdlog::logger > InitLogger(const std::string &name)
Create a spdlog logger, register it in the spdlog registry and initialize it with LehrFEM++ specific ...
Utilities for testing sanity of mesh data structures and tests involving meshes.
bool checkMeshCompleteness(const Mesh &mesh)
Function testing topological completeness of a mesh.
std::vector< std::pair< lf::base::RefEl, base::glb_idx_t > > isWatertightMesh(const Mesh &mesh, bool vertices_only)
check for match of entity geometries
std::shared_ptr< spdlog::logger > & WatertightLogger()
Logger that is used by isWatertightMesh() to output additional information.