PolyFEM
Loading...
Searching...
No Matches
ActiveSelectionUtils.cpp
Go to the documentation of this file.
2
4
5#include <Eigen/Core>
6
7#include <vector>
8#include <string>
9#include <memory>
10#include <cassert>
11#include <unordered_set>
12
13#include <spdlog/fmt/fmt.h>
14
16
17namespace polyfem::solver
18{
19
20 bool is_active_geom_nodes_valid(const Eigen::VectorXi &active_geom_nodes,
21 const std::vector<std::shared_ptr<legacy::State>> &states,
22 std::string &reason)
23 {
24 assert(!states.empty());
25
26 // Check state vertex num consistency.
27 int num = states[0]->mesh->n_vertices();
28 for (auto &s : states)
29 {
30 if (s->mesh->n_vertices() != num)
31 {
32 reason = "Mesh vertex num mismatch between states";
33 return false;
34 }
35 }
36
37 if (active_geom_nodes.size() == 0)
38 {
39 return true;
40 }
41
42 // Check active node index range.
43 int min_id = active_geom_nodes.minCoeff();
44 int max_id = active_geom_nodes.maxCoeff();
45 if (min_id < 0 || max_id >= num)
46 {
47 reason = fmt::format("Invalid active node range [{}, {}]", min_id, max_id);
48 return false;
49 }
50
51 // Check duplication.
52 std::unordered_set<int> id_set(active_geom_nodes.begin(), active_geom_nodes.end());
53 if (id_set.size() != active_geom_nodes.size())
54 {
55 reason = "Duplicate active node id";
56 return false;
57 }
58
59 return true;
60 }
61
62 bool is_active_dims_valid(const Eigen::VectorXi &active_dimensions,
63 const std::vector<std::shared_ptr<legacy::State>> &states,
64 std::string &reason)
65 {
66 assert(!states.empty());
67
68 // Check state dim consistency.
69 int dim = states[0]->mesh->dimension();
70 for (auto &s : states)
71 {
72 if (s->mesh->dimension() != dim)
73 {
74 reason = "Mesh dimension mismatch between states";
75 return false;
76 }
77 }
78
79 if (active_dimensions.size() == 0)
80 {
81 return true;
82 }
83
84 // Check active dim range.
85 int min_dim = active_dimensions.minCoeff();
86 int max_dim = active_dimensions.maxCoeff();
87 if (min_dim < 0 || max_dim >= dim)
88 {
89 reason = fmt::format("Invalid active dimension range [{}, {}]", min_dim, max_dim);
90 return false;
91 }
92
93 // Check duplication.
94 std::unordered_set<int> dim_set(active_dimensions.begin(), active_dimensions.end());
95 if (dim_set.size() != active_dimensions.size())
96 {
97 reason = "Duplicate dimensions";
98 return false;
99 }
100
101 return true;
102 }
103
104 bool is_active_dofs_valid(const Eigen::VectorXi &active_dofs,
105 const std::vector<std::shared_ptr<legacy::State>> &states,
106 std::string &reason)
107 {
108 assert(!states.empty());
109
110 // Check state ndof consistency.
111 int ndof = states[0]->ndof();
112 for (auto &s : states)
113 {
114 if (s->ndof() != ndof)
115 {
116 reason = "legacy::State ndof mismatch between states";
117 return false;
118 }
119 }
120
121 if (active_dofs.size() == 0)
122 {
123 return true;
124 }
125
126 // Check active dof index range.
127 const int min_id = active_dofs.minCoeff();
128 const int max_id = active_dofs.maxCoeff();
129 if (min_id < 0 || max_id >= ndof)
130 {
131 reason = fmt::format("Invalid active dof range [{}, {}]", min_id, max_id);
132 return false;
133 }
134
135 // Check duplication.
136 std::unordered_set<int> id_set(active_dofs.begin(), active_dofs.end());
137 if (id_set.size() != active_dofs.size())
138 {
139 reason = "Duplicate active dof id";
140 return false;
141 }
142
143 return true;
144 }
145
146 bool is_active_time_slices_valid(const Eigen::VectorXi &active_time_slices,
147 const std::vector<std::shared_ptr<legacy::State>> &states,
148 std::string &reason)
149 {
150 assert(!states.empty());
151
152 // Check state time_steps consistency.
153 int time_steps = states[0]->args["time"]["time_steps"];
154 for (auto &s : states)
155 {
156 if (int(s->args["time"]["time_steps"]) != time_steps)
157 {
158 reason = "time_steps mismatch between states";
159 return false;
160 }
161 }
162
163 if (active_time_slices.size() == 0)
164 {
165 return true;
166 }
167
168 // Check range.
169 const int min_id = active_time_slices.minCoeff();
170 const int max_id = active_time_slices.maxCoeff();
171 if (min_id < 0 || max_id >= time_steps)
172 {
173 reason = fmt::format("Invalid active time slice range [{}, {}]", min_id, max_id);
174 return false;
175 }
176
177 // Check duplication.
178 std::unordered_set<int> id_set(active_time_slices.begin(), active_time_slices.end());
179 if (id_set.size() != active_time_slices.size())
180 {
181 reason = "Duplicate active time slices";
182 return false;
183 }
184
185 return true;
186 }
187
188 bool is_active_dirichlet_boundary_ids_valid(const Eigen::VectorXi &active_boundary_ids,
189 const std::vector<std::shared_ptr<legacy::State>> &states,
190 std::string &reason)
191 {
192 assert(!states.empty());
193
194 if (active_boundary_ids.size() == 0)
195 {
196 return true;
197 }
198
199 // Check duplication.
200 std::unordered_set<int> id_set(active_boundary_ids.begin(), active_boundary_ids.end());
201 if (id_set.size() != active_boundary_ids.size())
202 {
203 reason = "Duplicate active boundary id";
204 return false;
205 }
206
207 // Validate ids exist and dimensions are all active.
208 int dim = states[0]->mesh->dimension();
209 for (auto &s : states)
210 {
211 // boundary_dims is a map where
212 // key: boundary id
213 // value: array<bool, 3>, true means that dimension is active.
214 auto boundry_dims = s->boundary_conditions_ids("dirichlet_boundary");
215 for (int i = 0; i < active_boundary_ids.size(); ++i)
216 {
217 // Check boundary id exists.
218 int id = active_boundary_ids(i);
219 auto iter = boundry_dims.find(id);
220 if (iter == boundry_dims.end())
221 {
222 reason = fmt::format("Invalid dirichlet boundary id {}", id);
223 return false;
224 }
225
226 if (s->mesh->dimension() != dim)
227 {
228 reason = "Inconsistent boundary node dimension";
229 return false;
230 }
231
232 // Check boundary does not have inactive dimension.
233 for (int d = 0; d < dim; ++d)
234 {
235 if (!iter->second[d])
236 {
237 reason = fmt::format("Dirichlet boundary id {} has inactive dimensions (not supported)", id);
238 return false;
239 }
240 }
241 }
242 }
243
244 return true;
245 }
246
247 bool is_active_dirichlet_node_valid(const Eigen::VectorXi &active_dirichlet_nodes,
248 const std::vector<std::shared_ptr<legacy::State>> &states,
249 std::string &reason)
250 {
251 assert(!states.empty());
252
253 // Basic node index checks (range/duplicates and mesh consistency).
254 if (!is_active_geom_nodes_valid(active_dirichlet_nodes, states, reason))
255 {
256 return false;
257 }
258
259 int vertex_num = states[0]->mesh->n_vertices();
260 int dim = states[0]->mesh->dimension();
261
262 for (auto &s : states)
263 {
264 if (s->mesh->n_vertices() != vertex_num)
265 {
266 reason = "Mesh vertex num mismatch between states";
267 return false;
268 }
269
270 if (s->mesh->dimension() != dim)
271 {
272 reason = "Mesh dimension mismatch between states";
273 return false;
274 }
275
276 if (!s->problem->has_nodal_dirichlet())
277 {
278 reason = "Nodal Dirichlet matrix is missing (cannot update nodal Dirichlet values)";
279 return false;
280 }
281
282 for (int i = 0; i < active_dirichlet_nodes.size(); ++i)
283 {
284 int v_in = active_dirichlet_nodes(i);
285 int v = s->in_node_to_node(v_in);
286 if (v < 0 || v >= vertex_num)
287 {
288 reason = fmt::format("Invalid in_node_to_node mapping: input vertex {} -> {}", v_in, v);
289 return false;
290 }
291
292 int tag = s->mesh->get_node_id(v);
293 if (!s->problem->is_nodal_dirichlet_boundary(v, tag))
294 {
295 reason = fmt::format("Input vertex {} is not a nodal Dirichlet node", v_in);
296 return false;
297 }
298
299 for (int d = 0; d < dim; ++d)
300 {
301 if (!s->problem->is_nodal_dimension_dirichlet(v, tag, d))
302 {
303 reason = fmt::format("Nodal Dirichlet at input vertex {} has inactive dimensions (not supported)", v_in);
304 return false;
305 }
306 }
307 }
308 }
309
310 return true;
311 }
312
313 bool is_active_pressure_boundary_ids_valid(const Eigen::VectorXi &active_boundary_ids,
314 const std::vector<std::shared_ptr<legacy::State>> &states,
315 std::string &reason)
316 {
317 assert(!states.empty());
318
319 if (active_boundary_ids.size() == 0)
320 {
321 return true;
322 }
323
324 // Check duplication.
325 std::unordered_set<int> id_set(active_boundary_ids.begin(), active_boundary_ids.end());
326 if (id_set.size() != active_boundary_ids.size())
327 {
328 reason = "Duplicate pressure boundary id";
329 return false;
330 }
331
332 for (auto &s : states)
333 {
334 for (auto id : active_boundary_ids)
335 {
336 if (!s->problem->is_boundary_pressure(id))
337 {
338 reason = fmt::format("Invalid pressure boundary id {}", id);
339 return false;
340 }
341 }
342 }
343
344 return true;
345 }
346
347} // namespace polyfem::solver
bool is_active_dirichlet_node_valid(const Eigen::VectorXi &active_dirichlet_nodes, const std::vector< std::shared_ptr< legacy::State > > &states, std::string &reason)
Validate active Dirichlet node ids selection given states.
bool is_active_time_slices_valid(const Eigen::VectorXi &active_time_slices, const std::vector< std::shared_ptr< legacy::State > > &states, std::string &reason)
Validate active time slices selection given states.
bool is_active_dirichlet_boundary_ids_valid(const Eigen::VectorXi &active_boundary_ids, const std::vector< std::shared_ptr< legacy::State > > &states, std::string &reason)
Validate active Dirichlet boundary ids selection given states.
bool is_active_geom_nodes_valid(const Eigen::VectorXi &active_geom_nodes, const std::vector< std::shared_ptr< legacy::State > > &states, std::string &reason)
Validate active geometry nodes selection given states.
bool is_active_pressure_boundary_ids_valid(const Eigen::VectorXi &active_boundary_ids, const std::vector< std::shared_ptr< legacy::State > > &states, std::string &reason)
Validate active pressure boundary ids selection given states.
bool is_active_dofs_valid(const Eigen::VectorXi &active_dofs, const std::vector< std::shared_ptr< legacy::State > > &states, std::string &reason)
Validate active solution space dofs selection given states.
bool is_active_dims_valid(const Eigen::VectorXi &active_dimensions, const std::vector< std::shared_ptr< legacy::State > > &states, std::string &reason)
Validate active dimensions selection given states.