Wildmeshing Toolkit
Loading...
Searching...
No Matches
SimWildMesh.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 <polysolve/nonlinear/Problem.hpp>
8#include <wmtk/envelope/Envelope.hpp>
9#include <wmtk/optimization/solver.hpp>
10#include <wmtk/simplex/Simplex.hpp>
11
12#include "ConnectedComponent.hpp"
13#include "Parameters.h"
14
15// clang-format off
16#include <wmtk/utils/DisableWarnings.hpp>
17#include <fastenvelope/FastEnvelope.h>
18#include <tbb/concurrent_queue.h>
19#include <tbb/concurrent_priority_queue.h>
20#include <tbb/concurrent_vector.h>
21#include <tbb/concurrent_map.h>
22#include <tbb/concurrent_unordered_map.h>
23#include <tbb/enumerable_thread_specific.h>
24#include <tbb/parallel_for.h>
25#include <tbb/task_arena.h>
26#include <tbb/parallel_sort.h>
27#include <wmtk/utils/EnableWarnings.hpp>
28#include <VolumeRemesher/embed.h>
29// clang-format on
30
31#include <igl/remove_unreferenced.h>
32#include <memory>
33
34#include "expression_parser/Expression.hpp"
35
36namespace wmtk::components::simwild {
37
39{
40public:
41 Vector3r m_pos; // exact position in rational
42 Vector3d m_posf; // position as double
47 bool m_is_rounded = false;
48
49 bool m_is_on_surface = false;
57 size_t m_order = 0;
58 std::vector<int> on_bbox_faces; // same as is_bbox_fs?
59
60 double m_sizing_scalar = 1;
61
65 size_t partition_id = 0;
66
68 VertexAttributes(const Vector3r& p);
69};
70
71
72// class EdgeAttributes
73// {
74// public:
75// bool m_is_on_open_boundary = false;
76// };
77
79{
80public:
84 bool m_is_surface_fs = false;
85
95 int m_is_bbox_fs = -1; //-1; 0~5
96
97 void reset()
98 {
99 m_is_surface_fs = false;
100 m_is_bbox_fs = -1;
101 }
102
103 void merge(const FaceAttributes& attr)
104 {
106 if (attr.m_is_bbox_fs >= 0) m_is_bbox_fs = attr.m_is_bbox_fs;
107 }
108};
109
111{
112public:
116 double m_quality;
121 CellTag tags;
122};
123
125{
126public:
127 using ExprPtr = expression_parser::ExpressionPtr;
128
129 int m_debug_print_counter = 0;
130 size_t m_tags_count = 0;
131 std::map<int64_t, std::string> m_tag_id_to_name;
132 std::map<std::string, int64_t> m_tag_name_to_id;
133
134 double time_env = 0.0;
135 igl::Timer isout_timer;
136 const double MAX_ENERGY = std::numeric_limits<double>::max();
137
138 Parameters& m_params;
139 std::vector<Vector3d> m_V_envelope;
140 std::vector<Vector3i> m_F_envelope;
141 std::shared_ptr<SampleEnvelope> m_envelope;
142 std::shared_ptr<SampleEnvelope> m_envelope_orig;
143 double m_envelope_eps = -1;
144
145 std::vector<std::tuple<ExprPtr, double>> m_sizing_field;
146
147 bool m_collapse_check_quality = true;
148
149 // for open boundary
150 std::shared_ptr<SampleEnvelope> m_order_2_edge_envelope; // todo: add sample envelope option
151
152 tbb::enumerable_thread_specific<std::unique_ptr<polysolve::nonlinear::Solver>> m_solver;
153
154 // scaling factors
155 double m_s_amips = -1;
156 double m_s_envelope = -1;
157
158 // When set, split_edge_after binary-searches vmid onto the zero-crossing of this function.
159 // Negative = stays on v1 side, positive = stays on v2 side.
160 std::function<double(const Vector3d&)> m_voronoi_split_fn = nullptr;
161
162 SimWildMesh(Parameters& _m_params, double envelope_eps, int _num_threads = 0)
163 : m_params(_m_params)
164 , m_envelope_eps(envelope_eps)
165 {
166 NUM_THREADS = _num_threads;
167 p_vertex_attrs = &m_vertex_attribute;
168 p_face_attrs = &m_face_attribute;
169 p_tet_attrs = &m_tet_attribute;
170 m_collapse_check_link_condition = false;
171 m_collapse_check_manifold = false;
172
173 // solver is lazily created on first use
174
175 optimization::deactivate_opt_logger();
176
177 m_s_amips = 1.;
178 m_s_envelope = 1. / (m_params.diag_l * m_params.eps * m_params.eps);
179
180 double& wa = m_params.w_amips;
181 double& we = m_params.w_envelope;
182 we = 1 - wa;
183 logger().info("w_envelope = {}", we);
184 }
185
186 ~SimWildMesh() {}
190 // using EdgeAttCol = wmtk::AttributeCollection<EdgeAttributes>;
191 VertAttCol m_vertex_attribute;
192 FaceAttCol m_face_attribute;
193 TetAttCol m_tet_attribute;
194 // EdgeAttCol m_edge_attribute;
195
196 // only used with unit tests
197 void create_mesh_attributes(
198 const std::vector<VertexAttributes>& _vertex_attribute,
199 const std::vector<TetAttributes>& _tet_attribute)
200 {
201 auto n_tet = _tet_attribute.size();
202 m_vertex_attribute.resize(_vertex_attribute.size());
203 m_face_attribute.resize(4 * n_tet);
204 m_tet_attribute.resize(n_tet);
205
206 for (auto i = 0; i < _vertex_attribute.size(); i++) {
207 m_vertex_attribute[i] = _vertex_attribute[i];
208 }
209 m_tet_attribute.m_attributes = tbb::concurrent_vector<TetAttributes>(_tet_attribute.size());
210 for (auto i = 0; i < _tet_attribute.size(); i++) {
211 m_tet_attribute[i] = _tet_attribute[i];
212 }
213 for (auto i = 0; i < _tet_attribute.size(); i++) {
214 m_tet_attribute[i].m_quality = get_quality(tuple_from_tet(i));
215 }
216 }
217
218 // TODO This should not be here but inside wmtk
219 void compute_vertex_partition()
220 {
221 auto partition_id = partition_TetMesh(*this, NUM_THREADS);
222 for (auto i = 0; i < vert_capacity(); i++)
223 m_vertex_attribute[i].partition_id = partition_id[i];
224 }
225
226 // TODO This should not be here but inside wmtk
227 void compute_vertex_partition_morton()
228 {
229 if (NUM_THREADS == 0) return;
230
231 wmtk::logger().info("Number of parts: {} by morton", NUM_THREADS);
232
233 tbb::task_arena arena(NUM_THREADS);
234
235 arena.execute([&] {
236 std::vector<Eigen::Vector3d> V_v(vert_capacity());
237
238 tbb::parallel_for(
239 tbb::blocked_range<int>(0, V_v.size()),
240 [&](tbb::blocked_range<int> r) {
241 for (int i = r.begin(); i < r.end(); i++) {
242 V_v[i] = m_vertex_attribute[i].m_posf;
243 }
244 });
245
246
247 struct sortstruct
248 {
249 int order;
251 };
252
253 std::vector<sortstruct> list_v;
254 list_v.resize(V_v.size());
255 // since the morton code requires a correct scale of input vertices,
256 // we need to scale the vertices if their coordinates are out of range
257 std::vector<Eigen::Vector3d> V = V_v; // this is for rescaling vertices
258 Eigen::Vector3d vmin, vmax;
259 vmin = V.front();
260 vmax = V.front();
261
262 for (size_t j = 0; j < V.size(); j++) {
263 for (int i = 0; i < 3; i++) {
264 vmin(i) = std::min(vmin(i), V[j](i));
265 vmax(i) = std::max(vmax(i), V[j](i));
266 }
267 }
268
269 // get_bb_corners(V, vmin, vmax);
270 Eigen::Vector3d center = (vmin + vmax) / 2;
271
272 tbb::parallel_for(tbb::blocked_range<int>(0, V.size()), [&](tbb::blocked_range<int> r) {
273 for (int i = r.begin(); i < r.end(); i++) {
274 V[i] = V[i] - center;
275 }
276 });
277
278 Eigen::Vector3d scale_point =
279 vmax - center; // after placing box at origin, vmax and vmin are symetric.
280
281 double xscale, yscale, zscale;
282 xscale = fabs(scale_point[0]);
283 yscale = fabs(scale_point[1]);
284 zscale = fabs(scale_point[2]);
285 double scale = std::max(std::max(xscale, yscale), zscale);
286 if (scale > 300) {
287 tbb::parallel_for(
288 tbb::blocked_range<int>(0, V.size()),
289 [&](tbb::blocked_range<int> r) {
290 for (int i = r.begin(); i < r.end(); i++) {
291 V[i] = V[i] / scale;
292 }
293 });
294 }
295
296 constexpr int multi = 1000;
297 tbb::parallel_for(tbb::blocked_range<int>(0, V.size()), [&](tbb::blocked_range<int> r) {
298 for (int i = r.begin(); i < r.end(); i++) {
299 list_v[i].morton = Resorting::MortonCode64(
300 int(V[i][0] * multi),
301 int(V[i][1] * multi),
302 int(V[i][2] * multi));
303 list_v[i].order = i;
304 }
305 });
306
307 const auto morton_compare = [](const sortstruct& a, const sortstruct& b) {
308 return (a.morton < b.morton);
309 };
310
311 tbb::parallel_sort(list_v.begin(), list_v.end(), morton_compare);
312
313 int interval = list_v.size() / NUM_THREADS + 1;
314
315 tbb::parallel_for(
316 tbb::blocked_range<int>(0, list_v.size()),
317 [&](tbb::blocked_range<int> r) {
318 for (int i = r.begin(); i < r.end(); i++) {
319 m_vertex_attribute[list_v[i].order].partition_id = i / interval;
320 }
321 });
322 });
323 }
324
325 size_t get_partition_id(const Tuple& loc) const
326 {
327 return m_vertex_attribute[loc.vid(*this)].partition_id;
328 }
329
330 void init_envelope(const MatrixXd& V, const MatrixXi& F, const bool use_exact);
331
332 CellTag string_set_to_cell_tag(const std::set<std::string>& str_set);
333
334 void set_sizing_field(const nlohmann::json& m_sizing_field_json);
335
336 double get_length2(const Tuple& l) const;
337
339
340 void write_msh(std::string file, const bool write_envelope = true);
341 void output_faces(std::string file, std::function<bool(const FaceAttributes&)> cond);
342
343public:
344 void split_all_edges();
345 bool split_edge_before(const Tuple& t) override;
346 bool split_edge_after(const Tuple& loc) override;
347
348 void smooth_all_vertices(const size_t n_iters);
349 bool smooth_before(const Tuple& t) override;
350 bool smooth_after(const Tuple& t) override;
351
352 void collapse_all_edges(bool is_limit_length = true);
353 bool collapse_edge_before(const Tuple& t) override;
354 bool collapse_edge_after(const Tuple& t) override;
355
356 void simplify();
357
358 size_t swap_all_edges_44();
359 bool swap_edge_44_before(const Tuple& t) override;
360 double swap_edge_44_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
361 override;
362 bool swap_edge_44_after(const Tuple& t) override;
363
364 size_t swap_all_edges_56();
365 bool swap_edge_56_before(const Tuple& t) override;
366 double swap_edge_56_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
367 override;
368 bool swap_edge_56_after(const Tuple& t) override;
369
370 size_t swap_all_edges_32();
371 bool swap_edge_before(const Tuple& t) override;
372 bool swap_edge_after(const Tuple& t) override;
373
374 size_t swap_all_faces();
375 bool swap_face_before(const Tuple& t) override;
376 bool swap_face_after(const Tuple& t) override;
377
378 size_t swap_all_edges_all();
379
383 bool is_inverted_f(const Tuple& loc) const;
384 bool is_inverted(const std::array<size_t, 4>& vs) const;
385 bool is_inverted(const Tuple& loc) const;
386 double get_quality(const std::array<size_t, 4>& vs) const;
387 double get_quality(const Tuple& loc) const;
388
389 std::vector<std::array<double, 12>> get_amips_assembles(const Tuple& t) const;
390
391 std::shared_ptr<polysolve::nonlinear::Problem> get_amips_energy(const Tuple& t) const;
392 std::shared_ptr<polysolve::nonlinear::Problem> get_envelope_energy(const Tuple& t) const;
393
401 bool round(const Tuple& loc);
402
407 bool all_rounded() const;
408
409 //
410 bool is_edge_on_surface(const Tuple& loc);
411 bool is_edge_on_bbox(const Tuple& loc);
412 //
413 void mesh_improvement(int max_its = 80);
414 std::tuple<double, double> local_operations(
415 const std::array<int, 4>& ops,
416 bool collapse_limit_length = true);
417 std::tuple<double, double> get_max_avg_energy();
418
419 bool check_attributes();
420
421 std::vector<std::array<size_t, 3>> get_faces_by_condition(
422 std::function<bool(const FaceAttributes&)> cond) const;
423
424 bool invariants(const std::vector<Tuple>& t) override; // this is now automatically checked
425
426 // debug use
427 std::atomic<int> cnt_split = 0, cnt_collapse = 0, cnt_swap = 0;
428
429private:
430 // tags: correspondence map from new tet-face node indices to in-triangle ids.
431 // built up while triangles are inserted.
432 tbb::concurrent_map<std::array<size_t, 3>, std::vector<int>> tet_face_tags;
433
435
437 {
438 // VertexAttributes vertex_info;
439 size_t v_new;
440 size_t v1_id;
441 size_t v2_id;
442 bool is_edge_on_surface = false;
443 bool is_edge_open_boundary = false;
444 std::vector<size_t> v1_param_type;
445 std::vector<size_t> v2_param_type;
446
447 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
448
453 std::map<simplex::Edge, TetAttributes> tets;
454 };
455 tbb::enumerable_thread_specific<SplitInfoCache> split_cache;
456
458 {
459 size_t v1_id;
460 size_t v2_id;
461 double max_energy;
462 double edge_length;
463 bool is_limit_length;
464
465 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
466 // all faces incident to the delete vertex (v1) that are on the tracked surface
467 std::vector<std::array<size_t, 3>> surface_faces;
468 // all edges incident to the deleted vertex(v1) that are on the open boundary
469 std::vector<std::array<size_t, 2>> boundary_edges;
470 std::vector<size_t> changed_tids;
471 std::vector<double> changed_energies;
472 };
473 tbb::enumerable_thread_specific<CollapseInfoCache> collapse_cache;
474
475
477 {
478 double max_energy;
479 std::map<std::array<size_t, 3>, FaceAttributes> changed_faces;
480 CellTag tet_tags;
481 };
482 tbb::enumerable_thread_specific<SwapInfoCache> swap_cache;
483
484public:
492 void init_from_image(
493 const MatrixXr& V,
494 const MatrixXi& T,
495 const MatrixSi& T_tags,
496 const std::vector<std::string>& tag_names);
497 void init_from_image(
498 const MatrixXd& V,
499 const MatrixXi& T,
500 const MatrixSi& T_tags,
501 const std::vector<std::string>& tag_names);
502
503 void init_surfaces_and_boundaries();
504
505 std::vector<std::array<size_t, 3>> triangulate_polygon_face(std::vector<Vector3r> points);
506
507 bool adjust_sizing_field_serial(double max_energy);
508
518 void find_order_2_edges();
528 bool is_order_2_edge(const Tuple& e) const;
529 bool is_order_2_edge(const std::array<size_t, 2>& e) const;
530
531 void write_vtu(const std::string& path);
532
533 void write_surface(const std::string& path) const;
534
535public:
536 // substructure functions
537
538 bool vertex_is_on_surface(const size_t vid) const override;
539
540 bool face_is_on_surface(const size_t fid) const override;
541
542 size_t get_order_of_vertex(const size_t vid) const override;
546 void init_vertex_order();
547
548public:
549 // Annotations
550
551 double tet_volume(const size_t tid) const;
552
556 std::vector<ConnectedComponent> compute_connected_components(const CellTag& tag_in) const;
557 std::vector<ConnectedComponent> compute_connected_components(const ExprPtr& expr) const;
558
576 std::vector<ConnectedComponent> find_holes(const std::vector<CellTag>& tag_in) const;
577
586 void compute_tag_boundary(const CellTag& tag, MatrixXd& V, MatrixXi& F) const;
587
595 void keep_largest_connected_component(
596 const std::vector<CellTag>& lcc_tags,
597 const size_t n_lcc = 1);
598
599 void fill_holes_topo(
600 const std::vector<CellTag>& fill_holes_tags,
601 double threshold = std::numeric_limits<double>::infinity());
602
603 void seal_connected_components(
604 const std::vector<CellTag>& tag_sets,
605 const std::vector<ConnectedComponent>& components);
606
607 void tight_seal_topo(
608 const std::vector<std::vector<CellTag>>& tight_seal_tag_sets,
609 double threshold = std::numeric_limits<double>::infinity());
610
611 void resolve_overlaps(const std::vector<std::array<ExprPtr, 2>>& intersecting_tags);
612
613 void replace_tags(const std::vector<CellTag>& tags_in, const std::vector<CellTag>& tags_out);
614
625 void tag_priority(const std::vector<int64_t>& tags);
626};
627
628} // namespace wmtk::components::simwild
Definition Morton.h:35
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
int m_is_bbox_fs
Definition SimWildMesh.h:95
bool m_is_surface_fs
Definition SimWildMesh.h:84
Definition SimWildMesh.h:125
Definition SimWildMesh.h:111
double m_quality
Definition SimWildMesh.h:116
CellTag tags
Definition SimWildMesh.h:121
size_t partition_id
Definition SimWildMesh.h:65
bool m_is_rounded
Definition SimWildMesh.h:47
size_t m_order
Definition SimWildMesh.h:57
Definition Parameters.h:7
std::map< simplex::Edge, TetAttributes > tets
Definition SimWildMesh.h:453