Wildmeshing Toolkit
Loading...
Searching...
No Matches
TetWildMesh.h
1#pragma once
2
3#include <igl/Timer.h>
4#include <wmtk/TetMesh.h>
5#include <wmtk/utils/Morton.h>
6#include <wmtk/utils/PartitionMesh.h>
7#include <wmtk/envelope/Envelope.hpp>
8#include "Parameters.h"
9
10// clang-format off
11#include <wmtk/utils/DisableWarnings.hpp>
12#include <fastenvelope/FastEnvelope.h>
13#include <tbb/concurrent_queue.h>
14#include <tbb/concurrent_priority_queue.h>
15#include <tbb/concurrent_vector.h>
16#include <tbb/concurrent_map.h>
17#include <tbb/concurrent_unordered_map.h>
18#include <tbb/enumerable_thread_specific.h>
19#include <tbb/parallel_for.h>
20#include <tbb/task_arena.h>
21#include <tbb/parallel_sort.h>
22#include <wmtk/utils/EnableWarnings.hpp>
23#include <VolumeRemesher/embed.h>
24// clang-format on
25
26#include <igl/remove_unreferenced.h>
27#include <memory>
28
29namespace wmtk::components::tetwild {
30
31// TODO: missing comments on what these attributes are
33{
34public:
35 Vector3r m_pos;
36 Vector3d m_posf;
37 bool m_is_rounded = false;
38
39 bool m_is_on_surface = false;
47 size_t m_order = 0;
48 std::vector<int> on_bbox_faces;
49
50 double m_sizing_scalar = 1;
51
52 size_t partition_id = 0;
53
54 // for open boundary
55 bool m_is_on_open_boundary = false;
56
58 VertexAttributes(const Vector3r& p);
59};
60
61
62// class EdgeAttributes
63// {
64// public:
65// bool m_is_on_open_boundary = false;
66// };
67
68// TODO: missing comments on what these attributes are
70{
71public:
72 double tag;
73
74 bool m_is_surface_fs = false; // 0; 1
75 int m_is_bbox_fs = -1; //-1; 0~5
76
77 void reset()
78 {
79 m_is_surface_fs = false;
80 m_is_bbox_fs = -1;
81 }
82
83 void merge(const FaceAttributes& attr)
84 {
85 m_is_surface_fs = m_is_surface_fs || attr.m_is_surface_fs;
86 if (attr.m_is_bbox_fs >= 0) m_is_bbox_fs = attr.m_is_bbox_fs;
87 }
88};
89
90// TODO: missing comments on what these attributes are
92{
93public:
94 double m_quality;
95 double m_winding_number_input = 0; // winding number w.r.t. the input
96 double m_winding_number_tracked = 0; // winding number w.r.t. the tracked surface
97 std::vector<double> m_winding_number_per_input;
98 int part_id = -1; // flood fill ID
99};
100
102{
103public:
104 double time_env = 0.0;
105 igl::Timer isout_timer;
106 const double MAX_ENERGY = 1e50;
107
108 Parameters& m_params;
109 SampleEnvelope& m_envelope;
110
111 // for open boundary
112 SampleEnvelope m_open_boundary_envelope; // todo: add sample envelope option
113
114 TetWildMesh(Parameters& _m_params, SampleEnvelope& _m_envelope, int _num_threads = 1)
115 : m_params(_m_params)
116 , m_envelope(_m_envelope)
117 {
118 NUM_THREADS = _num_threads;
119 p_vertex_attrs = &m_vertex_attribute;
120 p_face_attrs = &m_face_attribute;
121 p_tet_attrs = &m_tet_attribute;
122 m_collapse_check_link_condition = false;
123 m_collapse_check_manifold = false;
124 }
125
126 ~TetWildMesh() {}
130 // using EdgeAttCol = wmtk::AttributeCollection<EdgeAttributes>;
131 VertAttCol m_vertex_attribute;
132 FaceAttCol m_face_attribute;
133 TetAttCol m_tet_attribute;
134 // EdgeAttCol m_edge_attribute;
135
136 // only used with unit tests
137 void create_mesh_attributes(
138 const std::vector<VertexAttributes>& _vertex_attribute,
139 const std::vector<TetAttributes>& _tet_attribute)
140 {
141 auto n_tet = _tet_attribute.size();
142 m_vertex_attribute.resize(_vertex_attribute.size());
143 m_face_attribute.resize(4 * n_tet);
144 m_tet_attribute.resize(n_tet);
145
146 // new for edge
147 // m_edge_attribute.resize(6 * n_tet);
148
149 for (auto i = 0; i < _vertex_attribute.size(); i++)
150 m_vertex_attribute[i] = _vertex_attribute[i];
151 m_tet_attribute.m_attributes = tbb::concurrent_vector<TetAttributes>(_tet_attribute.size());
152 for (auto i = 0; i < _tet_attribute.size(); i++) m_tet_attribute[i] = _tet_attribute[i];
153 for (auto i = 0; i < _tet_attribute.size(); i++)
154 m_tet_attribute[i].m_quality = get_quality(tuple_from_tet(i));
155 }
156
157 // TODO This should not be here but inside wmtk
158 void compute_vertex_partition()
159 {
160 auto partition_id = partition_TetMesh(*this, NUM_THREADS);
161 for (auto i = 0; i < vert_capacity(); i++)
162 m_vertex_attribute[i].partition_id = partition_id[i];
163 }
164
165 // TODO This should not be here but inside wmtk
166 void compute_vertex_partition_morton()
167 {
168 if (NUM_THREADS == 0) return;
169
170 wmtk::logger().info("Number of parts: {} by morton", NUM_THREADS);
171
172 tbb::task_arena arena(NUM_THREADS);
173
174 arena.execute([&] {
175 std::vector<Eigen::Vector3d> V_v(vert_capacity());
176
177 tbb::parallel_for(
178 tbb::blocked_range<size_t>(0, V_v.size()),
179 [&](tbb::blocked_range<size_t> r) {
180 for (size_t i = r.begin(); i < r.end(); i++) {
181 V_v[i] = m_vertex_attribute[i].m_posf;
182 }
183 });
184
185
186 struct sortstruct
187 {
188 size_t order;
190 };
191
192 std::vector<sortstruct> list_v;
193 list_v.resize(V_v.size());
194 // since the morton code requires a correct scale of input vertices,
195 // we need to scale the vertices if their coordinates are out of range
196 std::vector<Eigen::Vector3d> V = V_v; // this is for rescaling vertices
197 Eigen::Vector3d vmin, vmax;
198 vmin = V.front();
199 vmax = V.front();
200
201 for (size_t j = 0; j < V.size(); j++) {
202 for (int i = 0; i < 3; i++) {
203 vmin(i) = std::min(vmin(i), V[j](i));
204 vmax(i) = std::max(vmax(i), V[j](i));
205 }
206 }
207
208 // get_bb_corners(V, vmin, vmax);
209 Eigen::Vector3d center = (vmin + vmax) / 2;
210
211 tbb::parallel_for(
212 tbb::blocked_range<size_t>(0, V.size()),
213 [&](tbb::blocked_range<size_t> r) {
214 for (size_t i = r.begin(); i < r.end(); i++) {
215 V[i] = V[i] - center;
216 }
217 });
218
219 Eigen::Vector3d scale_point =
220 vmax - center; // after placing box at origin, vmax and vmin are symetric.
221
222 double xscale, yscale, zscale;
223 xscale = fabs(scale_point[0]);
224 yscale = fabs(scale_point[1]);
225 zscale = fabs(scale_point[2]);
226 double scale = std::max(std::max(xscale, yscale), zscale);
227 if (scale > 300) {
228 tbb::parallel_for(
229 tbb::blocked_range<size_t>(0, V.size()),
230 [&](tbb::blocked_range<size_t> r) {
231 for (size_t i = r.begin(); i < r.end(); i++) {
232 V[i] = V[i] / scale;
233 }
234 });
235 }
236
237 constexpr int multi = 1000;
238 tbb::parallel_for(
239 tbb::blocked_range<size_t>(0, V.size()),
240 [&](tbb::blocked_range<size_t> r) {
241 for (size_t i = r.begin(); i < r.end(); i++) {
242 list_v[i].morton = Resorting::MortonCode64(
243 int(V[i][0] * multi),
244 int(V[i][1] * multi),
245 int(V[i][2] * multi));
246 list_v[i].order = i;
247 }
248 });
249
250 const auto morton_compare = [](const sortstruct& a, const sortstruct& b) {
251 return (a.morton < b.morton);
252 };
253
254 tbb::parallel_sort(list_v.begin(), list_v.end(), morton_compare);
255
256 size_t interval = list_v.size() / NUM_THREADS + 1;
257
258 tbb::parallel_for(
259 tbb::blocked_range<size_t>(0, list_v.size()),
260 [&](tbb::blocked_range<size_t> r) {
261 for (size_t i = r.begin(); i < r.end(); i++) {
262 m_vertex_attribute[list_v[i].order].partition_id = i / interval;
263 }
264 });
265 });
266 }
267
268 size_t get_partition_id(const Tuple& loc) const
269 {
270 return m_vertex_attribute[loc.vid(*this)].partition_id;
271 }
272
274
275 void output_mesh(std::string file);
276 void output_faces(std::string file, std::function<bool(const FaceAttributes&)> cond);
277
278 void init_from_delaunay_box_mesh(const std::vector<Eigen::Vector3d>& vertices);
279
280 void finalize_triangle_insertion(const std::vector<std::array<size_t, 3>>& faces);
281
282 void init_from_input_surface(
283 const std::vector<Vector3d>& vertices,
284 const std::vector<std::array<size_t, 3>>& faces,
285 const std::vector<size_t>& partition_id);
286 bool triangle_insertion_before(const std::vector<Tuple>& faces) override;
287 bool triangle_insertion_after(const std::vector<std::vector<Tuple>>& new_faces) override;
288
289public:
290 void split_all_edges();
291 bool split_edge_before(const Tuple& t) override;
292 bool split_edge_after(const Tuple& loc) override;
293
294 void smooth_all_vertices();
295 bool smooth_before(const Tuple& t) override;
296 bool smooth_after(const Tuple& t) override;
297
298 void collapse_all_edges(bool is_limit_length = true);
299 bool collapse_edge_before(const Tuple& t) override;
300 bool collapse_edge_after(const Tuple& t) override;
301
302 size_t swap_all_edges_44();
303 bool swap_edge_44_before(const Tuple& t) override;
304 double swap_edge_44_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
305 override;
306 bool swap_edge_44_after(const Tuple& t) override;
307
308 size_t swap_all_edges_56();
309 bool swap_edge_56_before(const Tuple& t) override;
310 double swap_edge_56_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
311 override;
312 bool swap_edge_56_after(const Tuple& t) override;
313
314 size_t swap_all_edges_32();
315 bool swap_edge_before(const Tuple& t) override;
316 bool swap_edge_after(const Tuple& t) override;
317
318 size_t swap_all_faces();
319 bool swap_face_before(const Tuple& t) override;
320 bool swap_face_after(const Tuple& t) override;
321
322 size_t swap_all_edges_all();
323
327 bool is_inverted_f(const Tuple& loc) const;
328 bool is_inverted(const std::array<size_t, 4>& vs) const;
329 bool is_inverted(const Tuple& loc) const;
330 double get_quality(const std::array<size_t, 4>& vs) const;
331 double get_quality(const Tuple& loc) const;
332 bool round(const Tuple& loc);
333 //
334 bool is_edge_on_surface(const Tuple& loc);
335 bool is_edge_on_bbox(const Tuple& loc);
340 bool is_vertex_on_boundary(const size_t vid);
341 //
342 void mesh_improvement(int max_its = 80);
346 void mesh_improvement_legacy(int max_its = 80);
347 std::tuple<double, double> local_operations(
348 const std::array<int, 4>& ops,
349 bool collapse_limit_length = true);
350 std::tuple<double, double> get_max_avg_energy();
351
358 void compute_winding_number(
359 const std::vector<Vector3d>& vertices = {},
360 const std::vector<std::array<size_t, 3>>& faces = {});
361
362 void compute_winding_numbers(const std::vector<std::string>& input_paths);
363
364 void filter_with_input_surface_winding_number();
365 void filter_with_tracked_surface_winding_number();
366 void filter_with_flood_fill();
367
368 bool check_attributes();
369
370 std::vector<std::array<size_t, 3>> get_faces_by_condition(
371 std::function<bool(const FaceAttributes&)> cond) const;
372
373 bool invariants(const std::vector<Tuple>& t) override; // this is now automatically checked
374
375 double get_length2(const Tuple& loc) const;
376 // debug use
377 std::atomic<int> cnt_split = 0, cnt_collapse = 0, cnt_swap = 0;
378
379private:
380 // tags: correspondence map from new tet-face node indices to in-triangle ids.
381 // built up while triangles are inserted.
382 tbb::concurrent_map<std::array<size_t, 3>, std::vector<int>> tet_face_tags;
383
385 {
386 // local info: for each face insertion
387 int face_id;
388 std::vector<std::array<size_t, 3>> old_face_vids;
389 };
390 tbb::enumerable_thread_specific<TriangleInsertionLocalInfoCache> triangle_insertion_local_cache;
391
393
395 {
396 // VertexAttributes vertex_info;
397 size_t v1_id;
398 size_t v2_id;
399 bool is_edge_on_surface = false;
400 bool is_edge_open_boundary = false;
401 size_t edge_order = 0;
402 std::vector<size_t> v1_param_type;
403 std::vector<size_t> v2_param_type;
404
405 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
406 };
407 tbb::enumerable_thread_specific<SplitInfoCache> split_cache;
408
410 {
411 size_t v1_id;
412 size_t v2_id;
413 double max_energy;
414 double edge_length;
415 bool is_limit_length;
416
417 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
418 // all faces incident to the delete vertex (v1) that are on the tracked surface
419 std::vector<std::array<size_t, 3>> surface_faces;
420 // all edges incident to the deleted vertex(v1) that are on the open boundary
421 std::vector<std::array<size_t, 2>> boundary_edges;
422 std::vector<size_t> changed_tids;
423 std::vector<double> changed_energies;
424
425 std::vector<std::array<size_t, 2>> failed_edges;
426
427 std::map<std::pair<size_t, size_t>, int> edge_link;
428 std::map<size_t, int> vertex_link;
429 size_t global_nonmani_ver_cnt;
430
431 // debug use
432 std::vector<size_t> one_ring_surface_vertices;
433 std::vector<std::pair<size_t, size_t>> one_ring_surface_edges;
434 std::vector<std::array<size_t, 3>> one_ring_surface;
435
436 // for geometry preservation
437 std::vector<size_t> edge_incident_param_type;
438 };
439 tbb::enumerable_thread_specific<CollapseInfoCache> collapse_cache;
440
441
443 {
444 double max_energy;
445 std::map<std::array<size_t, 3>, FaceAttributes> changed_faces;
446 };
447 tbb::enumerable_thread_specific<SwapInfoCache> swap_cache;
448
449
450 // for incremental tetwild
451public:
455 void insertion_by_volumeremesher_old(
456 const std::vector<Vector3d>& vertices,
457 const std::vector<std::array<size_t, 3>>& faces,
458 std::vector<Vector3r>& v_rational,
459 std::vector<std::array<size_t, 3>>& facets_after,
460 std::vector<bool>& is_v_on_input,
461 std::vector<std::array<size_t, 4>>& tets_after,
462 std::vector<bool>& tet_face_on_input_surface);
463
468 void insertion_by_volumeremesher(
469 const std::vector<Vector3d>& vertices,
470 const std::vector<std::array<size_t, 3>>& faces,
471 std::vector<Vector3r>& v_rational,
472 std::vector<std::array<size_t, 3>>& facets_after,
473 std::vector<bool>& is_v_on_input,
474 std::vector<std::array<size_t, 4>>& tets_after,
475 std::vector<bool>& tet_face_on_input_surface);
476
477 void init_from_Volumeremesher(
478 const std::vector<Vector3r>& v_rational,
479 const std::vector<std::array<size_t, 3>>& facets,
480 const std::vector<bool>& is_v_on_input,
481 const std::vector<std::array<size_t, 4>>& tets,
482 const std::vector<bool>& tet_face_on_input_surface);
483
484 void init_from_file(std::string input_dir);
485
486 std::vector<std::array<size_t, 3>> triangulate_polygon_face(std::vector<Vector3r> points);
487 bool check_polygon_face_validity(std::vector<Vector3r> points);
488
489 bool check_nondegenerate_tets();
490 void output_embedded_polygon_mesh(
491 std::string output_dir,
492 const std::vector<Vector3r>& v_rational,
493 const std::vector<std::vector<size_t>>& polygon_faces,
494 const std::vector<std::vector<size_t>>& polygon_cells,
495 const std::vector<bool>& polygon_faces_on_input_surface);
496
497 void output_embedded_polygon_surface_mesh(
498 std::string output_dir,
499 const std::vector<Vector3r>& v_rational,
500 const std::vector<std::vector<size_t>>& polygon_faces,
501 const std::vector<bool>& polygon_faces_on_input_surface);
502
503 void output_tetrahedralized_embedded_mesh(
504 std::string output_dir,
505 const std::vector<Vector3r>& v_rational,
506 const std::vector<std::array<size_t, 3>>& facets,
507 const std::vector<std::array<size_t, 4>>& tets,
508 const std::vector<bool>& tet_face_on_input_surface);
509
510 void output_init_tetmesh(std::string output_dir);
511
512 void output_tracked_surface(std::string output_file);
513
514 bool adjust_sizing_field_serial(double max_energy);
515
516 // for open boundary
517 void find_open_boundary();
518 bool is_open_boundary_edge(const Tuple& e);
519 bool is_open_boundary_edge(const std::array<size_t, 2>& e);
520
521public:
522 // substructure functions
523
524 bool vertex_is_on_surface(const size_t vid) const override;
525
526 bool face_is_on_surface(const size_t fid) const override;
527
528 size_t get_order_of_vertex(const size_t vid) const override;
532 void init_vertex_order();
533
534public:
535 // debug functions
536 int orient3D(
537 vol_rem::bigrational px,
538 vol_rem::bigrational py,
539 vol_rem::bigrational pz,
540 vol_rem::bigrational qx,
541 vol_rem::bigrational qy,
542 vol_rem::bigrational qz,
543 vol_rem::bigrational rx,
544 vol_rem::bigrational ry,
545 vol_rem::bigrational rz,
546 vol_rem::bigrational sx,
547 vol_rem::bigrational sy,
548 vol_rem::bigrational sz);
549
550 // bool checkTrackedFaces(
551 // std::vector<vol_rem::bigrational>& vol_coords,
552 // const std::vector<double>& surf_coords,
553 // std::vector<uint32_t>& facets,
554 // std::vector<uint32_t>& facets_on_input,
555 // const std::vector<uint32_t>& surf_tris);
556
557 int orient3D_wmtk_rational(
569 wmtk::Rational sz);
570
571 bool checkTrackedFaces_wmtk_rational(
572 std::vector<wmtk::Rational>& vol_coords,
573 const std::vector<double>& surf_coords,
574 std::vector<uint32_t>& facets,
575 std::vector<uint32_t>& facets_on_input,
576 const std::vector<uint32_t>& surf_tris);
577
578 bool check_vertex_param_type();
579
580 // for boolean operations
581 int flood_fill();
582
583 void save_paraview(const std::string& path, const bool use_hdf5);
584
585 // initialize sizing field (for topology preservation)
586 void init_sizing_field();
587
588public:
590 {
591 // tet mesh
592 MatrixXd V;
593 MatrixXi T;
594 // tracked surface
595 MatrixXi F;
596 // attributes
597 VectorXd t_amips;
598 VectorXd t_winding_number_input;
599 VectorXd t_winding_number_tracked;
600 MatrixXd t_winding_number_per_input;
601 VectorXi t_part;
602 };
603 // export functionality
604 ExportStruct export_mesh_data() const;
605};
606
607
608} // namespace wmtk::components::tetwild
Definition Morton.h:35
Definition Rational.hpp:10
Definition Envelope.hpp:56
a Tuple refers to a global vid and a global tet id, and a local edge id and local face id
Definition TetMesh.h:48
Definition TetMesh.h:23
size_t vert_capacity() const
get the current largest global vid
Definition TetMesh.h:354
Tuple tuple_from_tet(size_t tid) const
get a Tuple from global tetra index
Definition TetMesh.cpp:580
Definition TetWildMesh.h:92
Definition TetWildMesh.h:102
size_t m_order
Definition TetWildMesh.h:47
Definition Parameters.h:5