PolyFEM
Loading...
Searching...
No Matches
WildRemesher.cpp
Go to the documentation of this file.
1#include "WildRemesher.hpp"
2
6
7#include <wmtk/utils/TupleUtils.hpp>
8
9#include <unordered_map>
10#include <unordered_set>
11
12#define VERTEX_ATTRIBUTE_GETTER(name, attribute) \
13 template <class WMTKMesh> \
14 Eigen::MatrixXd WildRemesher<WMTKMesh>::name() const \
15 { \
16 Eigen::MatrixXd attributes = Eigen::MatrixXd::Constant(WMTKMesh::vert_capacity(), DIM, NaN); \
17 for (const Tuple &t : WMTKMesh::get_vertices()) \
18 attributes.row(t.vid(*this)) = vertex_attrs[t.vid(*this)].attribute; \
19 return attributes; \
20 }
21
22#define VERTEX_ATTRIBUTE_SETTER(name, attribute) \
23 template <class WMTKMesh> \
24 void WildRemesher<WMTKMesh>::name(const Eigen::MatrixXd &attributes) \
25 { \
26 for (const Tuple &t : WMTKMesh::get_vertices()) \
27 vertex_attrs[t.vid(*this)].attribute = attributes.row(t.vid(*this)); \
28 }
29
30namespace polyfem::mesh
31{
32 static constexpr double NaN = std::numeric_limits<double>::quiet_NaN();
33
34 template <class WMTKMesh>
36 const State &state,
37 const Eigen::MatrixXd &obstacle_displacements,
38 const Eigen::MatrixXd &obstacle_vals,
39 const double current_time,
40 const double starting_energy)
41 : Remesher(state, obstacle_displacements, obstacle_vals, current_time, starting_energy),
42 WMTKMesh()
43 {
44 }
45
46 template <typename WMTKMesh>
48 rank_edges(const Remesher::EdgeMap<double> &edge_energy, const json &args)
49 {
50 if (edge_energy.empty())
52
53 double min_energy = std::numeric_limits<double>::infinity();
54 double max_energy = -std::numeric_limits<double>::infinity();
55 std::vector<double> sorted_energies;
56 sorted_energies.reserve(edge_energy.size());
57 for (const auto &[edge, energy] : edge_energy)
58 {
59 min_energy = std::min(min_energy, energy);
60 max_energy = std::max(max_energy, energy);
61 sorted_energies.push_back(energy);
62 }
63 std::sort(sorted_energies.begin(), sorted_energies.end());
64
65 const double split_threshold = args["split"]["culling_threshold"];
66 const double split_tolerance = args["split"]["acceptance_tolerance"];
67 const double top_energy_threshold = (max_energy - min_energy) * split_threshold + min_energy;
68 const double top_element_threshold = sorted_energies[int(sorted_energies.size() * split_threshold)];
69 const double top_threshold = std::max(std::min(top_energy_threshold, top_element_threshold), std::min(1e-12, split_tolerance));
70
71 const double collapse_threshold = args["collapse"]["culling_threshold"];
72 const double bottom_energy_threshold = (max_energy - min_energy) * collapse_threshold + min_energy;
73 // const double bottom_element_threshold = sorted_energies[int(sorted_energies.size() * collapse_threshold)];
74 const double bottom_threshold = bottom_energy_threshold;
75
76 logger().info("min energy: {}, max energy: {}, thresholds: {}, {}", min_energy, max_energy, bottom_threshold, top_threshold);
77
79 for (const auto &[edge, energy] : edge_energy)
80 {
81 if (energy >= top_threshold)
83 else if (energy <= bottom_threshold)
85 else
87 }
88
89 return edge_ranks;
90 }
91
92 template <class WMTKMesh>
94 const Eigen::MatrixXd &rest_positions,
95 const Eigen::MatrixXd &positions,
96 const Eigen::MatrixXi &elements,
97 const Eigen::MatrixXd &projection_quantities,
98 const BoundaryMap<int> &boundary_to_id,
99 const std::vector<int> &body_ids,
100 const EdgeMap<double> &elastic_energy,
101 const EdgeMap<double> &contact_energy)
102 {
104 rest_positions, positions, elements, projection_quantities,
105 boundary_to_id, body_ids, elastic_energy, contact_energy);
106
107 total_volume = 0;
108 for (const Tuple &t : get_elements())
109 total_volume += element_volume(t);
110 assert(total_volume > 0);
111
112#ifndef NDEBUG
113 assert(get_elements().size() == elements.rows());
114 for (const Tuple &t : get_elements())
115 assert(!is_inverted(t));
116#endif
117
118 const auto edge_elastic_ranks = rank_edges<WMTKMesh>(elastic_energy, args);
119 const auto edge_contact_ranks = rank_edges<WMTKMesh>(contact_energy, args);
120
122 for (const auto &[edge, elastic_rank] : edge_elastic_ranks)
123 {
124 const auto contact_rank = edge_contact_ranks.empty() ? elastic_rank : edge_contact_ranks.at(edge);
125 if (elastic_rank == EdgeAttributes::EnergyRank::TOP || contact_rank == EdgeAttributes::EnergyRank::TOP)
126 edge_ranks[edge] = EdgeAttributes::EnergyRank::TOP;
127 else if (elastic_rank == EdgeAttributes::EnergyRank::BOTTOM && contact_rank == EdgeAttributes::EnergyRank::BOTTOM)
128 edge_ranks[edge] = EdgeAttributes::EnergyRank::BOTTOM;
129 else
130 edge_ranks[edge] = EdgeAttributes::EnergyRank::MIDDLE;
131 }
132
133 for (const Tuple &edge : WMTKMesh::get_edges())
134 {
135 const size_t e0 = edge.vid(*this);
136 const size_t e1 = edge.switch_vertex(*this).vid(*this);
137 edge_attr(edge.eid(*this)).energy_rank = edge_ranks.at({{e0, e1}});
138 }
139
140 // write_edge_ranks_mesh(edge_elastic_ranks, edge_contact_ranks);
142
143 // -------------------------------------------------------------------------
144 // Getters
145
146 VERTEX_ATTRIBUTE_GETTER(rest_positions, rest_position)
147 VERTEX_ATTRIBUTE_GETTER(positions, position)
148 VERTEX_ATTRIBUTE_GETTER(displacements, displacement())
149
150 template <class WMTKMesh>
151 Eigen::MatrixXi WildRemesher<WMTKMesh>::edges() const
152 {
153 const std::vector<Tuple> edges = WMTKMesh::get_edges();
154 Eigen::MatrixXi E = Eigen::MatrixXi::Constant(edges.size(), 2, -1);
155 for (int i = 0; i < edges.size(); ++i)
156 {
157 const Tuple &e = edges[i];
158 E(i, 0) = e.vid(*this);
159 E(i, 1) = e.switch_vertex(*this).vid(*this);
160 }
161 return E;
162 }
164 template <class WMTKMesh>
165 Eigen::MatrixXi WildRemesher<WMTKMesh>::elements() const
166 {
167 const std::vector<Tuple> elements = get_elements();
168 Eigen::MatrixXi F = Eigen::MatrixXi::Constant(elements.size(), dim() + 1, -1);
169 for (size_t i = 0; i < elements.size(); i++)
170 {
171 const auto vids = element_vids(elements[i]);
172
173 for (int j = 0; j < vids.size(); j++)
174 {
175 F(i, j) = vids[j];
176 }
177 }
178 return F;
179 }
180
181 template <class WMTKMesh>
183 {
184 Eigen::MatrixXd projection_quantities =
185 Eigen::MatrixXd::Constant(dim() * WMTKMesh::vert_capacity(), n_quantities(), NaN);
186
187 for (const Tuple &t : WMTKMesh::get_vertices())
188 {
189 const int vi = t.vid(*this);
190 projection_quantities.middleRows(dim() * vi, dim()) = vertex_attrs[vi].projection_quantities;
191 }
192
193 return projection_quantities;
194 }
196 template <class WMTKMesh>
197 std::vector<int> WildRemesher<WMTKMesh>::body_ids() const
198 {
199 const std::vector<Tuple> elements = get_elements();
200 std::vector<int> body_ids(elements.size(), -1);
201 for (size_t i = 0; i < elements.size(); i++)
202 {
203 body_ids[i] = element_attrs[element_id(elements[i])].body_id;
204 }
205 return body_ids;
207
208 template <class WMTKMesh>
210 const Eigen::VectorXi &vertex_to_basis) const
211 {
212 std::vector<int> boundary_nodes;
213
214 const std::unordered_map<int, std::array<bool, 3>> bcs =
215 state.boundary_conditions_ids("dirichlet_boundary");
216 std::vector<int> boundary_ids;
217 const std::vector<Tuple> boundary_facets = this->boundary_facets(&boundary_ids);
218 for (int i = 0; i < boundary_facets.size(); ++i)
219 {
220 const Tuple &t = boundary_facets[i];
221 const auto bc = bcs.find(boundary_ids[i]);
222
223 if (bc == bcs.end())
224 continue;
225
226 for (int d = 0; d < this->dim(); ++d)
227 {
228 if (!bc->second[d])
229 continue;
230
231 for (const size_t vid : facet_vids(t))
232 boundary_nodes.push_back(dim() * vertex_to_basis[vid] + d);
233 }
234 }
235
236 // Sort and remove the duplicate boundary_nodes.
237 std::sort(boundary_nodes.begin(), boundary_nodes.end());
238 auto new_end = std::unique(boundary_nodes.begin(), boundary_nodes.end());
239 boundary_nodes.erase(new_end, boundary_nodes.end());
240
241 return boundary_nodes;
242 }
243
244 template <class WMTKMesh>
245 std::vector<typename WMTKMesh::Tuple>
246 WildRemesher<WMTKMesh>::boundary_facets(std::vector<int> *boundary_ids) const
247 {
248 POLYFEM_REMESHER_SCOPED_TIMER("boundary_facets");
249
250 size_t element_capacity;
251 if constexpr (std::is_same_v<wmtk::TriMesh, WMTKMesh>)
252 element_capacity = WMTKMesh::tri_capacity();
253 else
254 element_capacity = WMTKMesh::tet_capacity();
255
256 const size_t max_tid = std::min(boundary_attrs.size() / FACETS_PER_ELEMENT, element_capacity);
257
258 std::vector<Tuple> boundary_facets;
259 for (int tid = 0; tid < max_tid; ++tid)
260 {
261 const Tuple t = tuple_from_element(tid);
262 if (!t.is_valid(*this))
263 continue;
264
265 for (int local_fid = 0; local_fid < FACETS_PER_ELEMENT; ++local_fid)
266 {
267 const Tuple facet_tuple = tuple_from_facet(tid, local_fid);
268 const int boundary_id = boundary_attrs[facet_id(facet_tuple)].boundary_id;
269 assert((boundary_id >= 0) == is_boundary_facet(facet_tuple));
270 if (boundary_id >= 0)
271 {
272 boundary_facets.push_back(facet_tuple);
273 if (boundary_ids)
274 boundary_ids->push_back(boundary_id);
275 }
277 }
278
279#ifndef NDEBUG
280 {
281 std::vector<size_t> boundary_facet_ids;
282 for (const Tuple &f : boundary_facets)
283 boundary_facet_ids.push_back(facet_id(f));
284 std::sort(boundary_facet_ids.begin(), boundary_facet_ids.end());
285
286 std::vector<size_t> gt_boundary_facet_ids;
287 for (const Tuple &f : get_facets())
288 if (is_boundary_facet(f))
289 gt_boundary_facet_ids.push_back(facet_id(f));
290 std::sort(gt_boundary_facet_ids.begin(), gt_boundary_facet_ids.end());
291
292 assert(boundary_facets.size() == gt_boundary_facet_ids.size());
293 assert(boundary_facet_ids == gt_boundary_facet_ids);
294 }
295#endif
296
297 return boundary_facets;
298 }
299
300 // -------------------------------------------------------------------------
301 // Setters
302
303 VERTEX_ATTRIBUTE_SETTER(set_rest_positions, rest_position)
304 VERTEX_ATTRIBUTE_SETTER(set_positions, position)
305
306 template <class WMTKMesh>
308 const Eigen::MatrixXd &projection_quantities)
309 {
310 assert(projection_quantities.rows() == dim() * WMTKMesh::vert_capacity());
311 m_n_quantities = projection_quantities.cols();
312
313 for (const Tuple &t : WMTKMesh::get_vertices())
314 {
315 const int vi = t.vid(*this);
316 vertex_attrs[vi].projection_quantities =
317 projection_quantities.middleRows(dim() * vi, dim());
318 }
319 }
320
321 template <class WMTKMesh>
323 const std::vector<bool> &fixed)
324 {
325 assert(fixed.size() == WMTKMesh::vert_capacity());
326 for (const Tuple &t : WMTKMesh::get_vertices())
327 vertex_attrs[t.vid(*this)].fixed = fixed[t.vid(*this)];
328 }
329
330 template <class WMTKMesh>
332 const std::vector<int> &body_ids)
333 {
334 const std::vector<Tuple> elements = get_elements();
335 for (int i = 0; i < elements.size(); ++i)
336 {
337 element_attrs[element_id(elements[i])].body_id = body_ids.at(i);
338 }
339 }
340
341 template <class WMTKMesh>
343 {
344 for (const Tuple &face : get_facets())
345 {
346 if constexpr (std::is_same_v<wmtk::TriMesh, WMTKMesh>)
347 {
348 assert(std::holds_alternative<EdgeMap<int>>(boundary_to_id));
349 const EdgeMap<int> &edge_to_boundary_id = std::get<EdgeMap<int>>(boundary_to_id);
350 boundary_attrs[facet_id(face)].boundary_id = edge_to_boundary_id.at(facet_vids(face));
351 }
352 else
353 {
354 assert(std::holds_alternative<FaceMap<int>>(boundary_to_id));
355 const FaceMap<int> &face_to_boundary_id = std::get<FaceMap<int>>(boundary_to_id);
356 boundary_attrs[facet_id(face)].boundary_id = face_to_boundary_id.at(facet_vids(face));
357 }
358
359#ifndef NDEBUG
360 if (is_boundary_facet(face))
361 assert(boundary_attrs[facet_id(face)].boundary_id >= 0);
362 else
363 assert(boundary_attrs[facet_id(face)].boundary_id == -1);
364#endif
365 }
366 }
367
368 // -------------------------------------------------------------------------
369
370 template <class WMTKMesh>
371 bool WildRemesher<WMTKMesh>::invariants(const std::vector<Tuple> &new_tris)
372 {
373 POLYFEM_REMESHER_SCOPED_TIMER("WildRemesher::invariants");
374 // for (auto &t : new_tris)
375 for (auto &t : get_elements())
376 {
377 if (is_inverted(t))
378 {
379 static int inversion_cnt = 0;
380 write_mesh(state.resolve_output_path(fmt::format("inversion_{:04d}.vtu", inversion_cnt++)));
381 log_and_throw_error("Inverted element found, invariants violated!");
382 return false;
383 }
384 }
385 return true;
386 }
387
388 // -------------------------------------------------------------------------
389 // Utils
390
391 template <class WMTKMesh>
393 {
394 const auto &e0 = vertex_attrs[e.vid(*this)].rest_position;
395 const auto &e1 = vertex_attrs[e.switch_vertex(*this).vid(*this)].rest_position;
396 return (e1 - e0).norm();
397 }
398
399 template <class WMTKMesh>
401 {
402 const auto &e0 = vertex_attrs[e.vid(*this)].position;
403 const auto &e1 = vertex_attrs[e.switch_vertex(*this).vid(*this)].position;
404 return (e1 - e0).norm();
405 }
406
407 template <class WMTKMesh>
410 {
411 const VectorNd &e0 = vertex_attrs[e.vid(*this)].rest_position;
412 const VectorNd &e1 = vertex_attrs[e.switch_vertex(*this).vid(*this)].rest_position;
413 return (e1 + e0) / 2.0;
414 }
415
416 template <class WMTKMesh>
419 {
420 const VectorNd &e0 = vertex_attrs[e.vid(*this)].position;
421 const VectorNd &e1 = vertex_attrs[e.switch_vertex(*this).vid(*this)].position;
422 return (e1 + e0) / 2.0;
423 }
424
425 template <class WMTKMesh>
426 std::vector<typename WMTKMesh::Tuple> WildRemesher<WMTKMesh>::get_edges_for_elements(
427 const std::vector<Tuple> &elements) const
428 {
429 std::vector<Tuple> edges;
430 for (auto t : elements)
431 for (int j = 0; j < EDGES_PER_ELEMENT; ++j)
432 edges.push_back(WMTKMesh::tuple_from_edge(element_id(t), j));
433 wmtk::unique_edge_tuples(*this, edges);
434 return edges;
435 }
436
437 template <class WMTKMesh>
439 {
440 double vol_tol;
441 std::vector<Tuple> adjacent_elements;
442 if constexpr (std::is_same_v<wmtk::TriMesh, WMTKMesh>)
443 {
444 adjacent_elements = {{e}};
445 const std::optional<Tuple> f = e.switch_face(*this);
446 if (f.has_value())
447 adjacent_elements.push_back(f.value());
448 }
449 else
450 {
451 adjacent_elements = get_incident_elements_for_edge(e);
452 }
453
454 Eigen::VectorXd adjacent_element_volumes(adjacent_elements.size());
455 for (int i = 0; i < adjacent_elements.size(); ++i)
456 adjacent_element_volumes[i] = element_volume(adjacent_elements[i]);
457
458 return adjacent_element_volumes;
459 }
460
461 template <class WMTKMesh>
462 void WildRemesher<WMTKMesh>::extend_local_patch(std::vector<Tuple> &patch) const
463 {
464 const size_t starting_size = patch.size();
465
466 std::unordered_set<size_t> element_ids;
467 for (const Tuple &t : patch)
468 element_ids.insert(element_id(t));
469
470 for (size_t i = 0; i < starting_size; ++i)
471 {
472 const size_t id = element_id(patch[i]);
473 for (int j = 0; j < EDGES_PER_ELEMENT; ++j)
474 {
475 const Tuple e = WMTKMesh::tuple_from_edge(id, j);
476
477 for (const Tuple &t : get_incident_elements_for_edge(e))
478 {
479 const size_t t_id = element_id(t);
480 if (element_ids.find(t_id) == element_ids.end())
481 {
482 patch.push_back(t);
483 element_ids.insert(t_id);
484 }
485 }
486 }
487 }
488 }
489
490 template <class WMTKMesh>
492 {
493 min.setConstant(dim(), std::numeric_limits<double>::infinity());
494 max.setConstant(dim(), -std::numeric_limits<double>::infinity());
495
496 for (const size_t vid : element_vids(t))
497 {
498 min = min.cwiseMin(vertex_attrs[vid].rest_position);
499 max = max.cwiseMax(vertex_attrs[vid].rest_position);
500 }
501 }
502
503 template <class WMTKMesh>
506 const EdgeMap<typename EdgeAttributes::EnergyRank> &contact_ranks) const
507 {
508 const std::vector<Tuple> edges = WMTKMesh::get_edges();
509
510 // Create two vertices per edge to get per edge values.
511 const int n_vertices = 2 * edges.size();
512
513 std::vector<std::vector<int>> elements(edges.size(), std::vector<int>(2));
514 Eigen::MatrixXd rest_positions(n_vertices, dim());
515 Eigen::MatrixXd displacements(n_vertices, dim());
516 Eigen::VectorXd energy_ranks(n_vertices);
517 Eigen::VectorXd elastic_energy_ranks(n_vertices);
518 Eigen::VectorXd contact_energy_ranks(n_vertices);
519
520 for (int ei = 0; ei < edges.size(); ei++)
521 {
522 const std::array<size_t, 2> vids = {{
523 edges[ei].vid(*this),
524 edges[ei].switch_vertex(*this).vid(*this),
525 }};
526
527 for (int vi = 0; vi < vids.size(); ++vi)
528 {
529 elements[ei][vi] = 2 * ei + vi;
530 rest_positions.row(elements[ei][vi]) = vertex_attrs[vids[vi]].rest_position;
531 displacements.row(elements[ei][vi]) = vertex_attrs[vids[vi]].displacement();
532 energy_ranks(elements[ei][vi]) = int(edge_attr(edges[ei].eid(*this)).energy_rank);
533 elastic_energy_ranks(elements[ei][vi]) = int(elastic_ranks.at(vids));
534 if (!contact_ranks.empty())
535 contact_energy_ranks(elements[ei][vi]) = int(contact_ranks.at(vids));
536 }
537 }
538
539 const double t0 = state.args["time"]["t0"];
540 const double dt = state.args["time"]["dt"];
541 const double save_dt = dt / 3;
542 // current_time = t0 + t * dt for t = 1, 2, 3, ...
543 // t = (current_time - t0) / dt
544 const int time_steps = int(round((current_time - t0) / save_dt));
545
546 // 0 -> 0 * dt + save_dt
547 // 1 -> 1 * dt + save_dt
548 // 2 -> 2 * dt + save_dt
549
550 const auto vtu_name = [&](int i) -> std::string {
551 return state.resolve_output_path(fmt::format("edge_ranks_{:d}.vtu", i));
552 };
553
554 paraviewo::VTUWriter writer;
555 writer.add_field("displacement", displacements);
556 writer.add_field("elastic_energy_rank", elastic_energy_ranks);
557 if (!contact_ranks.empty())
558 writer.add_field("contact_energy_rank", contact_energy_ranks);
559 writer.add_field("energy_rank", energy_ranks);
560 writer.write_mesh(vtu_name(time_steps - 3), rest_positions, elements, state.mesh->is_volume() ? paraviewo::CellType::Tetrahedron : paraviewo::CellType::Triangle);
561
562 writer.add_field("displacement", displacements);
563 writer.add_field("elastic_energy_rank", elastic_energy_ranks);
564 if (!contact_ranks.empty())
565 writer.add_field("contact_energy_rank", contact_energy_ranks);
566 writer.add_field("energy_rank", energy_ranks);
567 writer.write_mesh(vtu_name(time_steps - 2), rest_positions, elements, state.mesh->is_volume() ? paraviewo::CellType::Tetrahedron : paraviewo::CellType::Triangle);
568
569 writer.add_field("displacement", displacements);
570 writer.add_field("elastic_energy_rank", elastic_energy_ranks);
571 if (!contact_ranks.empty())
572 writer.add_field("contact_energy_rank", contact_energy_ranks);
573 writer.add_field("energy_rank", energy_ranks);
574 writer.write_mesh(vtu_name(time_steps - 1), rest_positions, elements, state.mesh->is_volume() ? paraviewo::CellType::Tetrahedron : paraviewo::CellType::Triangle);
575
576 state.out_geom.save_pvd(
577 state.resolve_output_path("edge_ranks.pvd"), vtu_name,
578 time_steps - 1, /*t0=*/save_dt, save_dt);
579 }
580
581 // -------------------------------------------------------------------------
582 // Template specializations
583
584 template class WildRemesher<wmtk::TriMesh>;
585 template class WildRemesher<wmtk::TetMesh>;
586
587} // namespace polyfem::mesh
#define POLYFEM_REMESHER_SCOPED_TIMER(name)
Definition Remesher.hpp:15
#define VERTEX_ATTRIBUTE_SETTER(name, attribute)
#define VERTEX_ATTRIBUTE_GETTER(name, attribute)
main class that contains the polyfem solver and all its state
Definition State.hpp:113
std::unordered_map< std::array< size_t, 2 >, T, polyfem::utils::HashUnorderedArray< size_t, 2 >, polyfem::utils::EqualUnorderedArray< size_t, 2 > > EdgeMap
Map from a (sorted) edge to an integer (ID)
Definition Remesher.hpp:29
std::variant< EdgeMap< T >, FaceMap< T > > BoundaryMap
Definition Remesher.hpp:42
std::unordered_map< std::array< size_t, 3 >, T, polyfem::utils::HashUnorderedArray< size_t, 3 >, polyfem::utils::EqualUnorderedArray< size_t, 3 > > FaceMap
Map from a (sorted) edge to an integer (ID)
Definition Remesher.hpp:35
virtual void init(const Eigen::MatrixXd &rest_positions, const Eigen::MatrixXd &positions, const Eigen::MatrixXi &elements, const Eigen::MatrixXd &projection_quantities, const BoundaryMap< int > &boundary_to_id, const std::vector< int > &body_ids, const EdgeMap< double > &elastic_energy, const EdgeMap< double > &contact_energy)
Initialize the mesh.
Definition Remesher.cpp:35
Eigen::MatrixXi elements() const override
Exports elements of the stored mesh.
Eigen::MatrixXd projection_quantities() const override
Exports projected quantities of the stored mesh.
double deformed_edge_length(const Tuple &e) const
void set_projection_quantities(const Eigen::MatrixXd &projection_quantities) override
Set projected quantities of the stored mesh.
void write_edge_ranks_mesh(const EdgeMap< typename EdgeAttributes::EnergyRank > &elastic_ranks, const EdgeMap< typename EdgeAttributes::EnergyRank > &contact_ranks) const
std::vector< Tuple > boundary_facets(std::vector< int > *boundary_ids=nullptr) const
Get the boundary facets of the mesh.
void set_body_ids(const std::vector< int > &body_ids) override
Set the body IDs of all elements.
virtual void init(const Eigen::MatrixXd &rest_positions, const Eigen::MatrixXd &positions, const Eigen::MatrixXi &elements, const Eigen::MatrixXd &projection_quantities, const BoundaryMap< int > &boundary_to_id, const std::vector< int > &body_ids, const EdgeMap< double > &elastic_energy, const EdgeMap< double > &contact_energy) override
Initialize the mesh.
typename WMTKMesh::Tuple Tuple
WildRemesher(const State &state, const Eigen::MatrixXd &obstacle_displacements, const Eigen::MatrixXd &obstacle_vals, const double current_time, const double starting_energy)
Construct a new WildRemesher object.
void set_boundary_ids(const BoundaryMap< int > &boundary_to_id) override
Set the boundary IDs of all edges.
std::vector< Tuple > get_edges_for_elements(const std::vector< Tuple > &elements) const
double rest_edge_length(const Tuple &e) const
Compute the length of an edge.
VectorNd rest_edge_center(const Tuple &e) const
Compute the center of the edge.
std::vector< int > body_ids() const override
Exports body ids of the stored mesh.
void element_aabb(const Tuple &t, polyfem::VectorNd &el_min, polyfem::VectorNd &el_max) const
Get a AABB for an element.
std::vector< int > boundary_nodes(const Eigen::VectorXi &vertex_to_basis) const override
Get the boundary nodes of the stored mesh.
Eigen::VectorXd edge_adjacent_element_volumes(const Tuple &e) const
void extend_local_patch(std::vector< Tuple > &patch) const
Extend the local patch by including neighboring elements.
Eigen::Matrix< double, DIM, 1 > VectorNd
void set_fixed(const std::vector< bool > &fixed) override
Set if a vertex is fixed.
bool invariants(const std::vector< Tuple > &new_tris) override
Check if invariants are satisfied.
VectorNd deformed_edge_center(const Tuple &e) const
WildTetRemesher::Tuple Tuple
Remesher::EdgeMap< typename WildRemesher< WMTKMesh >::EdgeAttributes::EnergyRank > rank_edges(const Remesher::EdgeMap< double > &edge_energy, const json &args)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, 3, 1 > VectorNd
Definition Types.hpp:11
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73