PolyFEM
Loading...
Searching...
No Matches
Problem.cpp
Go to the documentation of this file.
1#include "Problem.hpp"
2
3namespace polyfem
4{
5 using namespace basis;
6 using namespace mesh;
7 using namespace utils;
8
9 namespace assembler
10 {
11 Problem::Problem(const std::string &name)
12 : name_(name)
13 {
14 }
15
16 bool Problem::has_boundary(const BoundaryKind kind, const int tag)
17 {
18 if (tag <= 0)
19 return false;
20
21 switch (kind)
22 {
24 return (!might_have_no_dirichlet() && boundary_ids_.empty())
25 || std::find(boundary_ids_.begin(), boundary_ids_.end(), tag) != boundary_ids_.end();
27 return std::find(neumann_boundary_ids_.begin(), neumann_boundary_ids_.end(), tag) != neumann_boundary_ids_.end()
29 default:
30 return false;
31 }
32
33 return false;
34 }
35
37 const Mesh &mesh,
38 const BoundaryKind kind,
39 const int fe_space_id,
40 const std::vector<ElementBases> &bases,
41 const std::vector<LocalBoundary> &local_boundary,
42 std::vector<LocalBoundary> &selected_local_boundary,
43 std::vector<int> &boundary_nodes)
44 {
45 (void)fe_space_id;
46
47 selected_local_boundary.clear();
48 boundary_nodes.clear();
49
50 for (const LocalBoundary &lb : local_boundary)
51 {
52 LocalBoundary selected_lb(lb.element_id(), lb.type());
53
54 for (int i = 0; i < lb.size(); ++i)
55 {
56 const int primitive_g_id = lb.global_primitive_id(i);
57 const int tag = mesh.get_boundary_id(primitive_g_id);
58
59 if (has_boundary(kind, tag))
60 selected_lb.add_boundary_primitive(primitive_g_id, lb[i]);
61 }
62
63 if (!selected_lb.empty())
64 selected_local_boundary.emplace_back(selected_lb);
65 }
66
67 if (kind != BoundaryKind::Dirichlet)
68 return;
69
70 const int dim = is_scalar() ? 1 : mesh.dimension();
71
72 for (const LocalBoundary &lb : selected_local_boundary)
73 {
74 const auto &b = bases[lb.element_id()];
75 for (int i = 0; i < lb.size(); ++i)
76 {
77 const int primitive_global_id = lb.global_primitive_id(i);
78 const auto nodes = b.local_nodes_for_primitive(primitive_global_id, mesh);
79
80 for (long n = 0; n < nodes.size(); ++n)
81 {
82 auto &bs = b.bases[nodes(n)];
83 for (size_t g = 0; g < bs.global().size(); ++g)
84 {
85 const int base_index = bs.global()[g].index * dim;
86 for (int d = 0; d < dim; ++d)
87 {
88 if (is_dimension_dirichet(mesh.get_boundary_id(primitive_global_id), d))
89 boundary_nodes.push_back(base_index + d);
90 }
91 }
92 }
93 }
94 }
95
96 std::sort(boundary_nodes.begin(), boundary_nodes.end());
97 const auto end = std::unique(boundary_nodes.begin(), boundary_nodes.end());
98 boundary_nodes.resize(std::distance(boundary_nodes.begin(), end));
99 }
100
102 const Mesh &mesh,
103 const int fe_space_id,
104 const std::vector<LocalBoundary> &local_boundary,
105 std::unordered_map<int, std::vector<LocalBoundary>> &local_pressure_cavity)
106 {
107 (void)fe_space_id;
108
109 local_pressure_cavity.clear();
110
111 for (const LocalBoundary &lb : local_boundary)
112 {
113 for (int i = 0; i < lb.size(); ++i)
114 {
115 const int primitive_g_id = lb.global_primitive_id(i);
116 const int tag = mesh.get_boundary_id(primitive_g_id);
117
118 if (std::find(pressure_cavity_ids_.begin(), pressure_cavity_ids_.end(), tag) == pressure_cavity_ids_.end())
119 continue;
120
121 LocalBoundary cavity_lb(lb.element_id(), lb.type());
122 cavity_lb.add_boundary_primitive(primitive_g_id, lb[i]);
123 local_pressure_cavity[tag].emplace_back(cavity_lb);
124 }
125 }
126 }
127
129 const Mesh &mesh,
130 const BoundaryKind kind,
131 const int fe_space_id,
132 const int n_bases,
133 std::vector<int> &nodes)
134 {
135 (void)fe_space_id;
136
137 nodes.clear();
138
139 if (kind == BoundaryKind::Dirichlet && !(mesh.has_node_ids() || has_nodal_dirichlet()))
140 return;
141 if (kind == BoundaryKind::Neumann && !(mesh.has_node_ids() || has_nodal_neumann()))
142 return;
143 for (int n_id = 0; n_id < n_bases; ++n_id)
144 {
145 const int tag = mesh.get_node_id(n_id);
146
148 nodes.push_back(n_id);
149 else if (kind == BoundaryKind::Neumann && is_nodal_neumann_boundary(n_id, tag))
150 nodes.push_back(n_id);
151 }
152 }
153
155 const Mesh &mesh,
156 const int n_bases,
157 const std::vector<ElementBases> &bases,
158 const std::vector<ElementBases> &geom_bases,
159 const std::vector<ElementBases> &pressure_bases,
160 std::vector<LocalBoundary> &local_boundary,
161 std::vector<int> &boundary_nodes,
162 std::vector<LocalBoundary> &local_neumann_boundary,
163 std::vector<LocalBoundary> &local_pressure_boundary,
164 std::unordered_map<int, std::vector<LocalBoundary>> &local_pressure_cavity,
165 std::vector<int> &pressure_boundary_nodes,
166 std::vector<int> &dirichlet_nodes,
167 std::vector<int> &neumann_nodes)
168 {
169 std::vector<LocalBoundary> new_local_boundary;
170 std::vector<LocalBoundary> new_local_pressure_dirichlet_boundary;
171 local_neumann_boundary.clear();
172 local_pressure_boundary.clear();
173 local_pressure_cavity.clear();
174
175 for (auto it = local_boundary.begin(); it != local_boundary.end(); ++it)
176 {
177 const auto &lb = *it;
178 LocalBoundary new_lb(lb.element_id(), lb.type());
179 LocalBoundary new_neumann_lb(lb.element_id(), lb.type());
180 LocalBoundary new_pressure_lb(lb.element_id(), lb.type());
181 LocalBoundary new_pressure_dirichlet_lb(lb.element_id(), lb.type());
182 for (int i = 0; i < lb.size(); ++i)
183 {
184 LocalBoundary new_pressure_cavity_lb(lb.element_id(), lb.type());
185
186 const int primitive_g_id = lb.global_primitive_id(i);
187 const int tag = mesh.get_boundary_id(primitive_g_id);
188
189 if (tag <= 0)
190 continue;
191
192 if ((!might_have_no_dirichlet() && boundary_ids_.empty()) || std::find(boundary_ids_.begin(), boundary_ids_.end(), tag) != boundary_ids_.end())
193 new_lb.add_boundary_primitive(lb.global_primitive_id(i), lb[i]);
194 if (std::find(neumann_boundary_ids_.begin(), neumann_boundary_ids_.end(), tag) != neumann_boundary_ids_.end())
195 new_neumann_lb.add_boundary_primitive(lb.global_primitive_id(i), lb[i]);
197 new_neumann_lb.add_boundary_primitive(lb.global_primitive_id(i), lb[i]);
198 if (std::find(pressure_boundary_ids_.begin(), pressure_boundary_ids_.end(), tag) != pressure_boundary_ids_.end())
199 new_pressure_lb.add_boundary_primitive(lb.global_primitive_id(i), lb[i]);
200 if (std::find(pressure_cavity_ids_.begin(), pressure_cavity_ids_.end(), tag) != pressure_cavity_ids_.end())
201 new_pressure_cavity_lb.add_boundary_primitive(lb.global_primitive_id(i), lb[i]);
203 new_pressure_dirichlet_lb.add_boundary_primitive(lb.global_primitive_id(i), lb[i]);
204
205 if (!new_pressure_cavity_lb.empty())
206 {
207 if (local_pressure_cavity.find(tag) == local_pressure_cavity.end())
208 local_pressure_cavity[tag] = std::vector<LocalBoundary>();
209 local_pressure_cavity[tag].emplace_back(new_pressure_cavity_lb);
210 }
211 }
212
213 if (!new_lb.empty())
214 new_local_boundary.emplace_back(new_lb);
215 if (!new_neumann_lb.empty())
216 local_neumann_boundary.emplace_back(new_neumann_lb);
217 if (!new_pressure_lb.empty())
218 local_pressure_boundary.emplace_back(new_pressure_lb);
219 if (!new_pressure_dirichlet_lb.empty())
220 new_local_pressure_dirichlet_boundary.emplace_back(new_pressure_dirichlet_lb);
221 }
222 local_boundary.clear();
223 std::swap(local_boundary, new_local_boundary);
224
225 boundary_nodes.clear();
226 pressure_boundary_nodes.clear();
227
228 const int dim = is_scalar() ? 1 : mesh.dimension();
229
230 for (auto it = local_boundary.begin(); it != local_boundary.end(); ++it)
231 {
232 const auto &lb = *it;
233 const auto &b = bases[lb.element_id()];
234 for (int i = 0; i < lb.size(); ++i)
235 {
236 const int primitive_global_id = lb.global_primitive_id(i);
237 const auto nodes = b.local_nodes_for_primitive(primitive_global_id, mesh);
238
239 for (long n = 0; n < nodes.size(); ++n)
240 {
241 auto &bs = b.bases[nodes(n)];
242 for (size_t g = 0; g < bs.global().size(); ++g)
243 {
244 const int base_index = bs.global()[g].index * dim;
245 for (int d = 0; d < dim; ++d)
246 {
247 if (is_dimension_dirichet(mesh.get_boundary_id(primitive_global_id), d))
248 boundary_nodes.push_back(base_index + d);
249 }
250 }
251 }
252 }
253 }
254
255 for (auto it = new_local_pressure_dirichlet_boundary.begin(); it != new_local_pressure_dirichlet_boundary.end(); ++it)
256 {
257 const auto &lb = *it;
258 const auto &b = pressure_bases[lb.element_id()];
259 for (int i = 0; i < lb.size(); ++i)
260 {
261 const int primitive_global_id = lb.global_primitive_id(i);
262 const auto nodes = b.local_nodes_for_primitive(primitive_global_id, mesh);
263
264 for (long n = 0; n < nodes.size(); ++n)
265 {
266 auto &bs = b.bases[nodes(n)];
267 for (size_t g = 0; g < bs.global().size(); ++g)
268 {
269 const int base_index = bs.global()[g].index;
270 pressure_boundary_nodes.push_back(base_index);
271 }
272 }
273 }
274 }
275
277 {
278 for (int n_id = 0; n_id < n_bases; ++n_id)
279 {
280 const int tag = mesh.get_node_id(n_id);
281
282 if (is_nodal_dirichlet_boundary(n_id, tag))
283 {
284 dirichlet_nodes.push_back(n_id);
285
286 for (int d = 0; d < dim; ++d)
287 {
288 if (is_nodal_dimension_dirichlet(n_id, tag, d))
289 boundary_nodes.push_back(n_id * dim + d);
290 }
291 }
292 else if (is_nodal_neumann_boundary(n_id, tag))
293 {
294 neumann_nodes.push_back(n_id);
295 }
296 }
297 }
298
299 std::sort(boundary_nodes.begin(), boundary_nodes.end());
300 auto it = std::unique(boundary_nodes.begin(), boundary_nodes.end());
301 boundary_nodes.resize(std::distance(boundary_nodes.begin(), it));
302
303 std::sort(pressure_boundary_nodes.begin(), pressure_boundary_nodes.end());
304 auto it_ = std::unique(pressure_boundary_nodes.begin(), pressure_boundary_nodes.end());
305 pressure_boundary_nodes.resize(std::distance(pressure_boundary_nodes.begin(), it_));
306 }
307 } // namespace assembler
308} // namespace polyfem
bool has_boundary(const BoundaryKind kind, const int tag)
Definition Problem.cpp:16
virtual bool has_nodal_neumann()
Definition Problem.hpp:48
void setup_bc(const mesh::Mesh &mesh, const BoundaryKind kind, const int fe_space_id, const std::vector< basis::ElementBases > &bases, const std::vector< mesh::LocalBoundary > &local_boundary, std::vector< mesh::LocalBoundary > &selected_local_boundary, std::vector< int > &boundary_nodes)
std::vector< int > normal_aligned_neumann_boundary_ids_
Definition Problem.hpp:115
virtual bool is_dimension_dirichet(const int tag, const int dim) const
Definition Problem.hpp:67
void setup_pressure_cavity_bc(const mesh::Mesh &mesh, const int fe_space_id, const std::vector< mesh::LocalBoundary > &local_boundary, std::unordered_map< int, std::vector< mesh::LocalBoundary > > &local_pressure_cavity)
Definition Problem.cpp:101
virtual bool is_scalar() const =0
std::vector< int > pressure_boundary_ids_
Definition Problem.hpp:116
virtual bool is_nodal_neumann_boundary(const int n_id, const int tag)
Definition Problem.hpp:46
virtual bool might_have_no_dirichlet()
Definition Problem.hpp:66
Problem(const std::string &name)
Definition Problem.cpp:11
std::vector< int > splitting_pressure_boundary_ids_
Definition Problem.hpp:118
std::vector< int > boundary_ids_
Definition Problem.hpp:113
virtual bool is_nodal_dirichlet_boundary(const int n_id, const int tag)
Definition Problem.hpp:45
virtual bool is_nodal_dimension_dirichlet(const int n_id, const int tag, const int dim) const
Definition Problem.hpp:68
void setup_nodal_bc(const mesh::Mesh &mesh, const BoundaryKind kind, const int fe_space_id, const int n_bases, std::vector< int > &nodes)
Definition Problem.cpp:128
std::vector< int > neumann_boundary_ids_
Definition Problem.hpp:114
std::vector< int > pressure_cavity_ids_
Definition Problem.hpp:117
virtual bool has_nodal_dirichlet()
Definition Problem.hpp:47
Boundary primitive IDs for a single element.
void add_boundary_primitive(const int global_index, const int local_index)
Mark a boundary primitive as a part of the global boundary.
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:41
bool has_node_ids() const
checks if points selections are available
Definition Mesh.hpp:530
virtual int get_boundary_id(const int primitive) const
Get the boundary selection of an element (face in 3d, edge in 2d)
Definition Mesh.hpp:488
int dimension() const
utily for dimension
Definition Mesh.hpp:153
virtual int get_node_id(const int node_id) const
Get the boundary selection of a node.
Definition Mesh.hpp:497
str nodes
Definition p_bases.py:399