Wildmeshing Toolkit
Loading...
Searching...
No Matches
TriOptimizerMesh.h
1#pragma once
2
3#include <wmtk/OptimizerParameters.h>
4#include <wmtk/RationalPositions.h>
5#include <wmtk/SurfaceTagAttributes.h>
6#include <wmtk/TriMesh.h>
7#include <wmtk/Types.hpp>
8#include <wmtk/envelope/Envelope.hpp>
9#include <wmtk/optimization/SmoothVertex.hpp>
10#include <wmtk/optimization/solver.hpp>
11#include <wmtk/threading/enumerable_thread_specific.hpp>
12
13#include <spdlog/fmt/bundled/format.h>
14#include <polysolve/nonlinear/Problem.hpp>
15
16#include <atomic>
17#include <limits>
18#include <map>
19#include <memory>
20#include <set>
21#include <vector>
22
23namespace wmtk {
24
39{
40public:
42 {
43 Vector2d m_posf; // position as double
44 Vector2r m_pos; // exact position in rational
50 bool m_is_rounded = false;
51
52 bool m_is_on_surface = false;
53 std::vector<int> on_bbox_faces;
54
55 double m_sizing_scalar = 1;
56
57 size_t partition_id = 0;
58
60 VertexAttributes(const Vector2d& p)
61 : m_posf(p)
62 , m_pos(to_rational(p))
63 , m_is_rounded(true)
64 {}
65 VertexAttributes(const Vector2r& p)
66 : m_posf(to_double(p))
67 , m_pos(p)
68 {}
69 };
70
71 using EdgeAttributes = wmtk::SurfaceTagAttributes;
72
74 {
75 double m_quality;
76 double m_winding_number = 0;
77 std::set<int64_t> tags;
78 int part_id = -1;
79 };
80
81 using VertAttCol = AttributeCollection<VertexAttributes>;
82 using EdgeAttCol = AttributeCollection<EdgeAttributes>;
83 using FaceAttCol = AttributeCollection<FaceAttributes>;
84
85 VertAttCol m_vertex_attribute;
86 EdgeAttCol m_edge_attribute;
87 FaceAttCol m_face_attribute;
88
97
112
123
132 static constexpr double MAX_ENERGY = 1e50;
133
137
138 std::shared_ptr<SampleEnvelope> m_envelope;
139 double m_envelope_eps = -1;
140
143 double m_s_amips = -1;
144 double m_s_envelope = -1;
145
147 m_solver;
148
151
152 bool m_collapse_limit_length = true;
153 int m_debug_print_counter = 0;
158 std::string m_debug_pass_name;
159
160 size_t m_tags_count = 0;
161 std::map<int64_t, std::string> m_tag_id_to_name;
162 std::map<std::string, int64_t> m_tag_name_to_id;
163
165 : m_params(params)
166 {
167 m_vertex_attr_group.add(&m_vertex_attribute);
168 p_vertex_attrs = &m_vertex_attr_group;
169 m_edge_attr_group.add(&m_edge_attribute);
170 p_edge_attrs = &m_edge_attr_group;
171 m_face_attr_group.add(&m_face_attribute);
172 p_face_attrs = &m_face_attr_group;
173
174 m_s_amips = 1.;
179 m_s_envelope = 1. / (m_params.eps * m_params.eps);
180 }
181 ~TriOptimizerMesh() override = default;
182
183 size_t get_partition_id(const Tuple& loc) const
184 {
185 return m_vertex_attribute[loc.vid(*this)].partition_id;
186 }
187 void partition_mesh();
188 void partition_mesh_morton();
189
190 double get_length2(const Tuple& l) const;
191
200 bool is_inverted(const std::array<size_t, 3>& vs) const;
201 bool is_inverted(const Tuple& loc) const;
202 bool is_inverted(const size_t fid) const;
204 bool is_inverted_f(const Tuple& loc) const;
205 bool is_inverted_f(const size_t fid) const;
206
207 double get_quality(const std::array<size_t, 3>& vs) const;
208 double get_quality(const Tuple& loc) const;
209 double get_quality(const size_t fid) const;
210
211 std::tuple<double, double> get_max_avg_energy();
212
220 virtual void update_attributes() {}
221
224 void mesh_improvement(int max_its = 80);
225 std::tuple<double, double> local_operations(
226 const std::array<int, 4>& ops,
227 bool collapse_limit_length = true);
228
229 std::set<simplex::Edge> m_force_split_edges;
230 size_t m_force_split_count = 0;
231 std::unique_ptr<std::atomic<int>[]> m_high_valence_claim;
232 size_t m_high_valence_claim_size = 0;
233 std::atomic<size_t> m_high_valence_rejects = 0;
234
235 bool is_force_split_edge(const size_t v1, const size_t v2) const
236 {
237 return m_force_split_edges.find(simplex::Edge(v1, v2)) != m_force_split_edges.end();
238 }
239
240 void split_all_edges();
241 bool split_edge_before(const Tuple& t) override;
242 bool split_edge_after(const Tuple& loc) override;
243
244 void collapse_all_edges(bool is_limit_length = true);
245 bool collapse_edge_before(const Tuple& t) override;
246 bool collapse_edge_after(const Tuple& t) override;
247
259 size_t coarsen_mesh();
260
268 bool coarsen_collapse_edge(const Tuple& e, std::vector<Tuple>& new_tris);
269
272 {
273 size_t accepted = 0;
274 size_t cells_before = 0;
275 size_t cells_after = 0;
276 double max_energy_before = 0.;
277 double max_energy_after = 0.;
278 };
279 CoarsenStats m_coarsen_stats;
280
288 size_t swap_all_edges();
289 double swap_weight(const Tuple& t) const;
290 bool swap_edge_before(const Tuple& t) override;
291 bool swap_edge_after(const Tuple& t) override;
292
300 void smooth_all_vertices(size_t n_iters = 1);
301 bool smooth_before(const Tuple& t) override;
302 bool smooth_after(const Tuple& t) override;
303
304 Vector2d smoothing_position(size_t vid) const;
305 void set_smoothing_position(size_t vid, const Vector2d& p);
306 virtual bool smoothing_position_is_allowed(size_t vid, const Vector2d& p) const = 0;
307
329 virtual std::shared_ptr<SampleEnvelope> smoothing_energy_envelope(const size_t vid) const
330 {
331 return m_vertex_attribute.at(vid).m_is_on_surface ? m_envelope : nullptr;
332 }
333 virtual std::shared_ptr<SampleEnvelope> smoothing_containment_envelope(const size_t vid) const
334 {
335 return m_vertex_attribute.at(vid).m_is_on_surface ? m_envelope : nullptr;
336 }
337
350 virtual std::shared_ptr<polysolve::nonlinear::Problem> smoothing_extra_energy(
351 const size_t vid) const
352 {
353 return nullptr;
354 }
355
356 double active_quality_threshold() const
357 {
358 return m_params.skip_good_regions_margin * m_params.stop_energy;
359 }
360 virtual std::vector<size_t> active_vertices() const;
361
375 virtual double quality_rel(const size_t fid) const
376 {
377 return m_face_attribute.at(fid).m_quality / m_params.stop_energy;
378 }
379
384 bool round(const Tuple& v);
385
386protected:
389 virtual std::tuple<double, double> optimization_quality_stats();
390 virtual double optimization_stop_metric() const { return m_params.stop_energy; }
391 virtual size_t refine_sizing_around_worst(double max_metric) = 0;
392
405 virtual bool optimization_bare_coarsen_passes() const { return true; }
411 uint32_t m_op_epoch = 0;
412 virtual bool optimization_stop_at_float() const { return false; }
413
428 virtual bool optimization_stalled(double prev, double cur)
429 {
430 return (prev - cur) <= m_params.stuck_refine_stall_eps * (cur - optimization_stop_metric());
431 }
432
450 {
451 if (m_params.debug_output) {
452 write_smoothing_debug_output(fmt::format("debug_{}", m_debug_print_counter++));
453 }
454 }
455
456 virtual void collapse_pass_begin() {}
457 virtual void collapse_pass_end(size_t) {}
458 virtual bool collapse_before_vertex(size_t, size_t) { return true; }
459 virtual bool collapse_quality_allowed(size_t v1, size_t, double q, double ring_max) const
460 {
461 return !m_vertex_attribute.at(v1).m_is_rounded || q <= m_params.stop_energy ||
462 q <= ring_max;
463 }
464 virtual void collapse_after_vertex(size_t, size_t) {}
465
466 virtual bool split_adjust_position(size_t, const std::vector<Tuple>&) { return true; }
467 virtual void split_after_vertex(size_t) {}
468
469 virtual void write_smoothing_debug_output(const std::string& path) const = 0;
470
471 // RationalPositions supplies round_all_vertices() and round_and_check_all_rounded() on
472 // top of these three.
473 std::vector<size_t> all_vertex_ids() const override;
474 bool vertex_is_rounded(const size_t vid) const override
475 {
476 return m_vertex_attribute.at(vid).m_is_rounded;
477 }
478 // Equivalent to round() on the tuple get_vertices() would have yielded: round() reads only
479 // the vid and the one-ring, and the one-ring query is answered from
480 // m_vertex_connectivity[vid] regardless of which cell the tuple names.
481 bool round_vertex(const size_t vid) override { return round(tuple_from_vertex(vid)); }
482
483public:
484 bool is_edge_on_surface(const Tuple& loc) const;
485 bool is_edge_on_surface(const std::array<size_t, 2>& vids) const;
486 bool is_edge_on_bbox(const Tuple& loc) const;
487 bool is_edge_on_bbox(const std::array<size_t, 2>& vids) const;
488
489 bool vertex_is_on_surface(const size_t vid) const override
490 {
491 return m_vertex_attribute.at(vid).m_is_on_surface ||
492 !m_vertex_attribute.at(vid).on_bbox_faces.empty();
493 }
494 bool edge_is_on_surface(const std::array<size_t, 2>& vids) const override
495 {
496 if (!vertex_is_on_surface(vids[0]) || !vertex_is_on_surface(vids[1])) {
497 return false;
498 }
499
500 const auto [_, eid] = tuple_from_edge(vids);
501 bool on_surface = m_edge_attribute.at(eid).m_is_surface_fs;
502 bool on_bbox = m_edge_attribute.at(eid).m_is_bbox_fs >= 0;
503 return on_surface || on_bbox;
504 }
505
518 virtual std::shared_ptr<SampleEnvelope> surface_envelope_for_edge(
519 const std::array<size_t, 2>& vids) const
520 {
521 return m_envelope;
522 }
523
526 bool surface_segment_is_outside(const size_t a, const size_t b) const
527 {
528 const std::shared_ptr<SampleEnvelope> env = surface_envelope_for_edge({{a, b}});
529 if (!env) return false;
530 const auto& VA = m_vertex_attribute;
531 return env->is_outside(std::array<Vector2d, 2>{{VA[a].m_posf, VA[b].m_posf}});
532 }
533
534 std::vector<std::array<size_t, 2>> get_edges_by_condition(
535 std::function<bool(const EdgeAttributes&)> cond) const;
536
545 void gradation_smooth_sizing(double grade, const std::vector<size_t>& seeds);
546
547protected:
549 {
550 size_t v1_id = 0;
551 size_t v2_id = 0;
552 EdgeAttributes old_e_attrs;
553 std::map<simplex::Edge, EdgeAttributes> changed_edges;
554 std::map<size_t, FaceAttributes> faces;
555 };
557
559 {
560 size_t v1_id = 0;
561 size_t v2_id = 0;
562 double max_energy = 0.;
563 double edge_length = 0.;
564 std::vector<std::pair<EdgeAttributes, std::array<size_t, 2>>> changed_edges;
565 std::vector<std::array<size_t, 2>> surface_edges;
566 std::vector<size_t> changed_fids;
567 std::vector<double> changed_energies;
571 };
573
575 bool m_coarsen_mode = false;
576
577private:
579 {
580 double max_energy;
581 std::map<simplex::Edge, EdgeAttributes> changed_edges;
582 std::set<int64_t> face_tags;
583 };
585
595 {
596 std::vector<size_t> ring; // vertices to re-smooth, BFS order
597 std::vector<size_t> frontier;
598 std::vector<size_t> next;
599 std::vector<size_t> one_ring;
600 std::vector<uint32_t> stamp;
601 uint32_t epoch = 0;
602 VertexAttributes saved_vertex;
603 std::vector<std::pair<size_t, double>> saved_qualities;
604 };
606
608 const std::vector<size_t>&
609 collect_vertex_ball(const size_t* seeds, size_t n_seeds, int n, CoarsenScratch& scr) const;
610
613 double region_max_quality_rel(const std::vector<size_t>& vids) const;
614
616 bool smooth_vertex_reversible(size_t vid, CoarsenScratch& scr);
617
618 size_t collapse_all_edges_impl(bool is_limit_length, int lock_ring, size_t max_passes = 0);
619};
620
621} // namespace wmtk
Several attribute collections for the same simplex type, behind one container.
Definition AttributeCollection.hpp:132
The rounded/exact bookkeeping shared by every mesh that keeps both coordinates.
Definition RationalPositions.h:21
Whether a codimension-1 simplex is tracked surface, and which bbox side it lies on.
Definition SurfaceTagAttributes.h:15
int m_is_bbox_fs
Which bbox side this simplex is on; -1 for none.
Definition SurfaceTagAttributes.h:20
bool m_is_surface_fs
Is this simplex part of the tracked surface.
Definition SurfaceTagAttributes.h:18
Definition TriMesh.h:32
Definition TriMesh.h:28
Tuple tuple_from_edge(size_t vid1, size_t vid2, size_t fid) const
Definition TriMesh.cpp:2202
Tuple tuple_from_vertex(size_t vid) const
Definition TriMesh.h:937
What triwild and simwild's 2D mesh share.
Definition TriOptimizerMesh.h:39
void smooth_all_vertices(size_t n_iters=1)
Run TriWild's vertex-smoothing pass.
Definition TriOptimizerMeshSmooth.cpp:63
bool smooth_after(const Tuple &t) override
User specified modifications and desideras after an edge smooth.
Definition TriOptimizerMeshSmooth.cpp:25
bool is_inverted_f(const Tuple &loc) const
Inversion check using only the double positions.
Definition TriOptimizerMesh.cpp:458
bool vertex_is_rounded(const size_t vid) const override
Whether this vertex's double position is currently trusted.
Definition TriOptimizerMesh.h:474
bool vertex_is_on_surface(const size_t vid) const override
Is a vertex part of the substructure.
Definition TriOptimizerMesh.h:489
std::vector< size_t > all_vertex_ids() const override
Every live vertex, in the mesh's own iteration order.
Definition TriOptimizerMesh.cpp:518
bool smooth_vertex_reversible(size_t vid, CoarsenScratch &scr)
One smoothing attempt on vid, restoring everything it wrote if it is rejected.
Definition TriOptimizerMeshCollapse.cpp:444
AttributeContainerGroup m_edge_attr_group
What p_edge_attrs points at, so a derived class can register more.
Definition TriOptimizerMesh.h:111
AttributeContainerGroup m_vertex_attr_group
What p_vertex_attrs points at, so a derived class can register more.
Definition TriOptimizerMesh.h:96
virtual std::shared_ptr< SampleEnvelope > surface_envelope_for_edge(const std::array< size_t, 2 > &vids) const
Envelope the tracked-surface segment vids must stay inside.
Definition TriOptimizerMesh.h:518
size_t coarsen_mesh()
Coarsen the mesh without letting the max energy rise.
Definition TriOptimizerMeshCollapse.cpp:485
bool swap_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge swap including 1.can't swap on boundary edge....
Definition TriOptimizerMesh.cpp:328
virtual double quality_rel(const size_t fid) const
A face's quality relative to the quality it is required to reach; <= 1 means it meets it.
Definition TriOptimizerMesh.h:375
virtual std::shared_ptr< SampleEnvelope > smoothing_energy_envelope(const size_t vid) const
The envelope this vertex is PULLED TOWARD while smoothing, and the one it is CONTAINED BY afterwards....
Definition TriOptimizerMesh.h:329
bool coarsen_collapse_edge(const Tuple &e, std::vector< Tuple > &new_tris)
One collapse under the coarsening rules, outside a coarsening pass.
Definition TriOptimizerMeshCollapse.cpp:473
static constexpr double MAX_ENERGY
The sentinel get_quality returns for a face AMIPS2D cannot score.
Definition TriOptimizerMesh.h:132
void gradation_smooth_sizing(double grade, const std::vector< size_t > &seeds)
Monotone (only-decreasing) gradation smoothing of the sizing field.
Definition TriOptimizerMesh.cpp:384
bool m_coarsen_mode
Set for the duration of coarsen_mesh(); read-only while a pass is running.
Definition TriOptimizerMesh.h:575
size_t swap_all_edges()
Run TriWild's quality-improving interior edge-flip pass.
Definition TriOptimizerMesh.cpp:281
const std::vector< size_t > & collect_vertex_ball(const size_t *seeds, size_t n_seeds, int n, CoarsenScratch &scr) const
Vertices within n edges of seeds, in BFS order. Uses coarsen_scratch.
Definition TriOptimizerMeshCollapse.cpp:377
bool edge_is_on_surface(const std::array< size_t, 2 > &vids) const override
Is an edge part of the substructure.
Definition TriOptimizerMesh.h:494
TriOptimizerMesh(OptimizerParameters &params)
Definition TriOptimizerMesh.h:164
virtual bool optimization_stalled(double prev, double cur)
Whether an iteration that moved the metric from prev to cur is stalled, and the sizing refinement sho...
Definition TriOptimizerMesh.h:428
bool surface_segment_is_outside(const size_t a, const size_t b) const
Definition TriOptimizerMesh.h:526
AttributeContainerGroup m_face_attr_group
What p_face_attrs points at, so a derived class can register more.
Definition TriOptimizerMesh.h:122
optimization::SmoothRejectCounters m_smooth_rejects
Why smoothing attempts were refused, reported once per pass.
Definition TriOptimizerMesh.h:150
OptimizerParameters & m_params
Definition TriOptimizerMesh.h:136
std::string m_debug_pass_name
Definition TriOptimizerMesh.h:158
double m_s_amips
Definition TriOptimizerMesh.h:143
bool swap_edge_after(const Tuple &t) override
User specified modifications and desideras after an edge swap.
Definition TriOptimizerMesh.cpp:357
bool collapse_edge_after(const Tuple &t) override
User specified modifications and desideratas after an edge collapse.
Definition TriOptimizerMeshCollapse.cpp:300
bool round_vertex(const size_t vid) override
Definition TriOptimizerMesh.h:481
bool round(const Tuple &v)
Round a vertex position to floating point, if that inverts no incident face.
Definition TriOptimizerMesh.cpp:529
virtual bool optimization_bare_coarsen_passes() const
Whether the loop opens and closes with BARE collapse passes.
Definition TriOptimizerMesh.h:405
int m_iterations_used
Shared TriWild/SimWild outer optimization schedule.
Definition TriOptimizerMesh.h:223
bool split_edge_after(const Tuple &loc) override
User specified modifications and desideratas after an edge split.
Definition TriOptimizerMeshSplit.cpp:171
double region_max_quality_rel(const std::vector< size_t > &vids) const
Definition TriOptimizerMeshCollapse.cpp:433
virtual std::shared_ptr< polysolve::nonlinear::Problem > smoothing_extra_energy(const size_t vid) const
An extra term the application adds to this vertex's smoothing objective, or null.
Definition TriOptimizerMesh.h:350
virtual std::tuple< double, double > optimization_quality_stats()
Definition TriOptimizerMesh.cpp:27
bool split_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge split.
Definition TriOptimizerMeshSplit.cpp:101
virtual void optimization_debug_checkpoint()
Called at every pass boundary, whether or not debug output is on.
Definition TriOptimizerMesh.h:449
bool collapse_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge collapse including the link check as collapse...
Definition TriOptimizerMeshCollapse.cpp:98
uint32_t m_op_epoch
Definition TriOptimizerMesh.h:411
virtual void update_attributes()
Update the attributes of the mesh after an iteration of operations.
Definition TriOptimizerMesh.h:220
bool smooth_before(const Tuple &t) override
User specified preparations and desideratas for an edge smooth.
Definition TriOptimizerMeshSmooth.cpp:12
Definition Simplex.hpp:46
Definition enumerable_thread_specific.hpp:26
The parameters tetwild, triwild and simwild all share.
Definition OptimizerParameters.h:29
Per-thread buffers for the coarsening composite, so it allocates nothing.
Definition TriOptimizerMesh.h:595
What coarsen_mesh() achieved, for the run report. Zeroed when the pass is off.
Definition TriOptimizerMesh.h:272
Definition TriOptimizerMesh.h:559
double region_max_rel_before
Definition TriOptimizerMesh.h:570
Definition TriOptimizerMesh.h:74
Definition TriOptimizerMesh.h:549
Definition TriOptimizerMesh.h:579
Definition TriOptimizerMesh.h:42
bool m_is_rounded
Definition TriOptimizerMesh.h:50
Why a smoothing attempt was refused, counted per pass.
Definition SmoothVertex.hpp:31