PolyFEM
Loading...
Searching...
No Matches
BarycentricBasis2d.cpp
Go to the documentation of this file.
1
4
6
7#include <memory>
8
9namespace polyfem
10{
11 using namespace assembler;
12 using namespace mesh;
13 using namespace quadrature;
14
15 namespace basis
16 {
17
18 namespace
19 {
20 std::vector<int> compute_nonzero_bases_ids(const Mesh2D &mesh, const int element_index,
21 const std::vector<ElementBases> &bases,
22 const Eigen::MatrixXd &poly, std::vector<LocalBoundary> &local_boundary)
23 {
24 const int n_edges = mesh.n_face_vertices(element_index);
25
26 std::vector<int> local_to_global(n_edges);
27 LocalBoundary lb(element_index, BoundaryType::POLYGON);
28
29 Navigation::Index index = mesh.get_index_from_face(element_index);
30 for (int i = 0; i < n_edges; ++i)
31 {
32 bool found = false;
33
34 Navigation::Index index1 = mesh.next_around_vertex(index);
35 while (index1.face != index.face)
36 {
37 if (index1.face < 0)
38 break;
39 if (found)
40 break;
41
42 const ElementBases &bs = bases[index1.face];
43
44 for (const auto &b : bs.bases)
45 {
46 for (const auto &x : b.global())
47 {
48 const int global_node_id = x.index;
49 if ((x.node - poly.row(i)).norm() < 1e-10)
50 {
51 local_to_global[i] = global_node_id;
52 found = true;
53 assert(b.global().size() == 1);
54 break;
55 }
56 }
57 if (found)
58 break;
59 }
60
61 index1 = mesh.next_around_vertex(index1);
62 }
63
64 index1 = mesh.next_around_vertex(mesh.switch_edge(index));
65
66 while (index1.face != index.face)
67 {
68 if (index1.face < 0)
69 break;
70 if (found)
71 break;
72
73 const ElementBases &bs = bases[index1.face];
74
75 for (const auto &b : bs.bases)
76 {
77 for (const auto &x : b.global())
78 {
79 const int global_node_id = x.index;
80 if ((x.node - poly.row(i)).norm() < 1e-10)
81 {
82 local_to_global[i] = global_node_id;
83 found = true;
84 assert(b.global().size() == 1);
85 break;
86 }
87 }
88 if (found)
89 break;
90 }
91
92 index1 = mesh.next_around_vertex(index1);
93 }
94
95 if (!found)
96 local_to_global[i] = -1;
97
98 if (mesh.is_boundary_edge(index.edge) || mesh.get_boundary_id(index.edge) > 0)
99 lb.add_boundary_primitive(index.edge, i);
100
101 index = mesh.next_around_face(index);
102 }
103
104 if (!lb.empty())
105 {
106 local_boundary.emplace_back(lb);
107 }
108
109 return local_to_global;
110 }
111
112 } // anonymous namespace
113
115
117 const std::string &assembler_name,
118 const int dim,
119 const Mesh2D &mesh,
120 const int n_bases,
121 const int quadrature_order,
122 const int mass_quadrature_order,
123 const std::function<void(const Eigen::MatrixXd &, const Eigen::RowVector2d &, Eigen::MatrixXd &, const double)> bc,
124 const std::function<void(const Eigen::MatrixXd &, const Eigen::RowVector2d &, Eigen::MatrixXd &, const double)> bc_prime,
125 std::vector<ElementBases> &bases,
126 std::vector<LocalBoundary> &local_boundary,
127 std::map<int, Eigen::MatrixXd> &mapped_boundary)
128 {
129 assert(!mesh.is_volume());
130
131 Eigen::MatrixXd polygon;
132
133 // int new_nodes = 0;
134
135 std::map<int, int> new_nodes;
136
137 PolygonQuadrature poly_quadr;
138 for (int e = 0; e < mesh.n_elements(); ++e)
139 {
140 if (!mesh.is_polytope(e))
141 {
142 continue;
143 }
144
145 polygon.resize(mesh.n_face_vertices(e), 2);
146
147 for (int i = 0; i < mesh.n_face_vertices(e); ++i)
148 {
149 const int gid = mesh.face_vertex(e, i);
150 polygon.row(i) = mesh.point(gid);
151 }
152
153 std::vector<int> local_to_global = compute_nonzero_bases_ids(mesh, e, bases, polygon, local_boundary);
154
155 for (int i = 0; i < local_to_global.size(); ++i)
156 {
157 if (local_to_global[i] >= 0)
158 continue;
159
160 const int gid = mesh.face_vertex(e, i);
161 const auto other_gid = new_nodes.find(gid);
162 if (other_gid != new_nodes.end())
163 local_to_global[i] = other_gid->second;
164 else
165 {
166 const int tmp = new_nodes.size() + n_bases;
167 new_nodes[gid] = tmp;
168 local_to_global[i] = tmp;
169 }
170 }
171
172 ElementBases &b = bases[e];
173 b.has_parameterization = false;
174
175 // Compute quadrature points for the polygon
176 Quadrature tmp_quadrature;
177 poly_quadr.get_quadrature(polygon, quadrature_order > 0 ? quadrature_order : AssemblerUtils::quadrature_order(assembler_name, 1, AssemblerUtils::BasisType::POLY, 2), tmp_quadrature);
178
179 Quadrature tmp_mass_quadrature;
180 poly_quadr.get_quadrature(polygon, mass_quadrature_order > 0 ? mass_quadrature_order : AssemblerUtils::quadrature_order("Mass", 1, AssemblerUtils::BasisType::POLY, 2), tmp_mass_quadrature);
181
182 b.set_quadrature([tmp_quadrature](Quadrature &quad) { quad = tmp_quadrature; });
183 b.set_mass_quadrature([tmp_mass_quadrature](Quadrature &quad) { quad = tmp_mass_quadrature; });
184
185 const double tol = 1e-10;
186 b.set_bases_func([polygon, tol, bc](const Eigen::MatrixXd &uv, std::vector<AssemblyValues> &val) {
187 Eigen::MatrixXd tmp;
188 val.resize(polygon.rows());
189 for (size_t i = 0; i < polygon.rows(); ++i)
190 {
191 val[i].val.resize(uv.rows(), 1);
192 }
193
194 for (int i = 0; i < uv.rows(); ++i)
195 {
196 bc(polygon, uv.row(i), tmp, tol);
197
198 for (size_t j = 0; j < tmp.size(); ++j)
199 {
200 val[j].val(i) = tmp(j);
201 }
202 }
203 });
204 b.set_grads_func([polygon, tol, bc_prime](const Eigen::MatrixXd &uv, std::vector<AssemblyValues> &val) {
205 Eigen::MatrixXd tmp;
206 val.resize(polygon.rows());
207 for (size_t i = 0; i < polygon.rows(); ++i)
208 {
209 val[i].grad.resize(uv.rows(), 2);
210 }
211
212 for (int i = 0; i < uv.rows(); ++i)
213 {
214 bc_prime(polygon, uv.row(i), tmp, tol);
215 assert(tmp.rows() == polygon.rows());
216
217 for (size_t j = 0; j < tmp.rows(); ++j)
218 {
219 val[j].grad.row(i) = tmp.row(j);
220 }
221 }
222 });
223
224 b.set_local_node_from_primitive_func([e](const int primitive_id, const Mesh &mesh) {
225 const auto &mesh2d = dynamic_cast<const Mesh2D &>(mesh);
226 auto index = mesh2d.get_index_from_face(e);
227
228 int le;
229 for (le = 0; le < mesh2d.n_face_vertices(e); ++le)
230 {
231 if (index.edge == primitive_id)
232 break;
233 index = mesh2d.next_around_face(index);
234 }
235 assert(index.edge == primitive_id);
236 Eigen::VectorXi result(2);
237 result(0) = le;
238 result(1) = (le + 1) % mesh2d.n_face_vertices(e);
239 return result;
240 });
241
242 // Set the bases which are nonzero inside the polygon
243 const int n_poly_bases = int(local_to_global.size());
244 b.bases.resize(n_poly_bases);
245 for (int i = 0; i < n_poly_bases; ++i)
246 {
247 b.bases[i].init(-1, local_to_global[i], i, polygon.row(i));
248 }
249
250 // Polygon boundary after geometric mapping from neighboring elements
251 mapped_boundary[e] = polygon;
252 }
253
254 return new_nodes.size();
255 }
256
257 } // namespace basis
258} // namespace polyfem
double val
Definition Assembler.cpp:86
Quadrature quadrature
int x
static int quadrature_order(const std::string &assembler, const int basis_degree, const BasisType &b_type, const int dim)
utility for retrieving the needed quadrature order to precisely integrate the given form on the given...
static int build_bases(const std::string &assembler_name, const int dim, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, const std::function< void(const Eigen::MatrixXd &, const Eigen::RowVector2d &, Eigen::MatrixXd &, const double)> bc, const std::function< void(const Eigen::MatrixXd &, const Eigen::RowVector2d &, Eigen::MatrixXd &, const double)> bc_prime, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, Eigen::MatrixXd > &mapped_boundary)
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
void set_bases_func(EvalBasesFunc fun)
void set_quadrature(const QuadratureFunction &fun)
void set_local_node_from_primitive_func(LocalNodeFromPrimitiveFunc fun)
sets mapping from local nodes to global nodes
void set_grads_func(EvalBasesFunc fun)
std::vector< Basis > bases
one basis function per node in the element
void set_mass_quadrature(const QuadratureFunction &fun)
bool is_volume() const override
checks if mesh is volume
Definition Mesh2D.hpp:25
virtual Navigation::Index get_index_from_face(int f, int lv=0) const =0
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:39
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Definition Mesh.hpp:161
bool is_polytope(const int el_id) const
checks if element is polygon compatible
Definition Mesh.cpp:365
virtual RowVectorNd point(const int global_index) const =0
point coordinates
virtual int n_face_vertices(const int f_id) const =0
number of vertices of a face
virtual int face_vertex(const int f_id, const int lv_id) const =0
id of the face vertex
void get_quadrature(const Eigen::MatrixXd &poly, const int order, Quadrature &quadr)
Gets the quadrature points & weights for a polygon.