Wildmeshing Toolkit
Loading...
Searching...
No Matches
TetOptimizerMesh.h
1#pragma once
2
3#include <wmtk/OptimizerParameters.h>
4#include <wmtk/RationalPositions.h>
5#include <wmtk/SurfaceTagAttributes.h>
6#include <wmtk/TetMesh.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/simplex/Simplex.hpp>
12#include <wmtk/threading/enumerable_thread_specific.hpp>
13#include <wmtk/utils/SurfaceTopology.hpp>
14
15#include <igl/Timer.h>
16
17#include <array>
18#include <atomic>
19#include <cmath>
20#include <functional>
21#include <map>
22#include <memory>
23#include <set>
24#include <vector>
25
26namespace wmtk {
27
46{
47public:
49 {
50 Vector3r m_pos; // exact position in rational
51 Vector3d m_posf; // position as double
57 bool m_is_rounded = false;
58
59 bool m_is_on_surface = false;
67 size_t m_order = 0;
68 std::vector<int> on_bbox_faces;
69
70 double m_sizing_scalar = 1;
71
73 size_t partition_id = 0;
74
76 VertexAttributes(const Vector3r& p);
77 };
78
80
82 using FaceAttCol = AttributeCollection<FaceAttributes>;
83
84 VertAttCol m_vertex_attribute;
85 FaceAttCol m_face_attribute;
86
94
109
118 static constexpr double MAX_ENERGY = 1e50;
119
123
125 std::shared_ptr<SampleEnvelope> m_envelope;
126
129 double m_s_amips = 1.;
130 double m_s_envelope = -1.;
131
132 double time_env = 0.0;
133 igl::Timer isout_timer;
134
138
145
149
153 std::set<simplex::Edge> m_force_split_edges;
156
157 bool is_force_split_edge(const size_t v1, const size_t v2) const
158 {
159 return m_force_split_edges.find(simplex::Edge(v1, v2)) != m_force_split_edges.end();
160 }
161
163 std::unique_ptr<std::atomic<int>[]> m_high_valence_claim;
164 size_t m_high_valence_claim_size = 0;
165 std::atomic<size_t> m_high_valence_rejects = 0;
166
167 explicit TetOptimizerMesh(OptimizerParameters& params, std::shared_ptr<SampleEnvelope> env)
168 : m_params(params)
169 , m_envelope(std::move(env))
170 {
171 m_vertex_attr_group.add(&m_vertex_attribute);
172 p_vertex_attrs = &m_vertex_attr_group;
173 m_face_attr_group.add(&m_face_attribute);
174 p_face_attrs = &m_face_attr_group;
175 }
176 ~TetOptimizerMesh() override = default;
177
186 virtual double cell_quality(const size_t tid) const = 0;
187 virtual void set_cell_quality(const size_t tid, const double q) = 0;
188
205 virtual double quality_rel(const size_t tid) const
206 {
207 return std::cbrt(cell_quality(tid)) / m_params.stop_energy;
208 }
209
210 // TODO This should not be here but inside wmtk
211 void compute_vertex_partition();
212 void compute_vertex_partition_morton();
213
214 size_t get_partition_id(const Tuple& loc) const
215 {
216 return m_vertex_attribute[loc.vid(*this)].partition_id;
217 }
218
219 double get_length2(const Tuple& l) const;
220
221 bool is_inverted(const std::array<size_t, 4>& vs) const;
222 bool is_inverted(const Tuple& loc) const;
224 bool is_inverted_f(const Tuple& loc) const;
225
226 double get_quality(const std::array<size_t, 4>& vs) const;
227 double get_quality(const Tuple& loc) const;
228 std::tuple<double, double> get_max_avg_energy();
229
237 virtual void update_attributes() {}
238
241 int m_debug_print_counter = 0;
247 std::string m_debug_pass_name;
248 void mesh_improvement(int max_its = 80);
249 std::tuple<double, double> local_operations(
250 const std::array<int, 4>& ops,
251 bool collapse_limit_length = true);
252
257 bool round(const Tuple& v);
258
259protected:
260 // RationalPositions supplies round_all_vertices() and round_and_check_all_rounded() on
261 // top of these three.
262 std::vector<size_t> all_vertex_ids() const override;
263 bool vertex_is_rounded(const size_t vid) const override
264 {
265 return m_vertex_attribute.at(vid).m_is_rounded;
266 }
267 // Equivalent to round() on the tuple get_vertices() would have yielded: round() reads only
268 // the vid and the one-ring, and the one-ring query is answered from
269 // m_vertex_connectivity[vid] regardless of which cell the tuple names.
270 bool round_vertex(const size_t vid) override { return round(tuple_from_vertex(vid)); }
271
272public:
273 bool is_edge_on_surface(const Tuple& loc);
274 bool is_edge_on_bbox(const Tuple& loc);
286 virtual bool is_open_boundary_edge(const Tuple& e) { return false; }
293 int edge_incident_surface_face_count(const Tuple& e);
294
308 virtual std::shared_ptr<SampleEnvelope> surface_envelope_for_face(
309 const std::array<size_t, 3>& vids) const
310 {
311 return m_envelope;
312 }
313
316 bool surface_triangle_is_outside(const size_t a, const size_t b, const size_t c) const
317 {
318 const std::shared_ptr<SampleEnvelope> env = surface_envelope_for_face({{a, b, c}});
319 if (!env) return false;
320 const auto& VA = m_vertex_attribute;
321 return env->is_outside({{VA[a].m_posf, VA[b].m_posf, VA[c].m_posf}});
322 }
323
324 bool vertex_is_on_surface(const size_t vid) const override;
325 bool face_is_on_surface(const size_t fid) const override;
326 size_t get_order_of_vertex(const size_t vid) const override;
327
328 std::vector<std::array<size_t, 3>> get_faces_by_condition(
329 std::function<bool(const FaceAttributes&)> cond) const;
330
331 void output_faces(std::string file, std::function<bool(const FaceAttributes&)> cond);
332
334 void gradation_smooth_sizing(double grade, const std::vector<size_t>& seeds);
335
345 {
346 const double e = m_params.skip_good_regions_margin * m_params.stop_energy;
347 return e * e * e;
348 }
349
352 virtual std::vector<size_t> active_vertices() const;
353
354 // TetWild's split engine. SimWild inherits it and customizes only application data,
355 // annotation-only placement, and order-2 metadata through the hooks below.
356 void split_all_edges();
357 bool split_edge_before(const Tuple& t) override;
358 bool split_edge_after(const Tuple& loc) override;
359
360 // TetWild's collapse engine. SimWild customizes only application policy/metadata.
361 void collapse_all_edges(bool is_limit_length = true);
362 bool collapse_edge_before(const Tuple& t) override;
363 bool collapse_edge_after(const Tuple& t) override;
364
374 size_t coarsen_mesh();
375
383 bool coarsen_collapse_edge(const Tuple& e, std::vector<Tuple>& new_tets);
384
387 {
388 size_t accepted = 0;
389 size_t cells_before = 0;
390 size_t cells_after = 0;
391 double max_energy_before = 0.;
392 double max_energy_after = 0.;
393 };
394 CoarsenStats m_coarsen_stats;
395
396 // TetWild's complete swap engine. SimWild inherits these operations and customizes only
397 // the tag bookkeeping through the hooks below.
398 size_t swap_all_edges_32();
399 bool swap_edge_before(const Tuple& t) override;
400 bool swap_edge_after(const Tuple& t) override;
401
402 size_t swap_all_edges_44();
403 bool swap_edge_44_before(const Tuple& t) override;
404 bool swap_edge_44_accept_case(const std::array<size_t, 2>& new_edge) override;
405 bool swap_edge_44_after(const Tuple& t) override;
406
407 size_t swap_all_edges_56();
408 bool swap_edge_56_before(const Tuple& t) override;
409 bool swap_edge_56_accept_case(const std::array<size_t, 3>& new_face) override;
410 bool swap_edge_56_after(const Tuple& t) override;
411
412 size_t swap_all_faces();
413 bool swap_face_before(const Tuple& t) override;
414 bool swap_face_after(const Tuple& t) override;
415 size_t swap_all_edges_all();
416
417 bool prepare_surface_flip(const Tuple& t, const std::vector<size_t>& incident_tets);
418
420 SurfaceTopoSignature surface_topology_signature() const
421 {
422 return wmtk::utils::surface_topology_signature(*this, [this](size_t fid) {
423 return m_face_attribute[fid].m_is_surface_fs;
424 });
425 }
426 void warn_if_surface_topology_changed(const SurfaceTopoSignature& before, const char* where)
427 const
428 {
429 wmtk::utils::warn_if_surface_topology_changed(before, surface_topology_signature(), where);
430 }
431
432 // Operation diagnostics shared by TetWild and SimWild.
433 std::atomic<int> cnt_swap = 0;
434 std::atomic<int> cnt_surface_swap = 0;
435 std::atomic<int> cnt_surface_swap_32 = 0, cnt_surface_swap_44 = 0, cnt_surface_swap_56 = 0;
436
437 double swap_edge_44_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
438 override;
439 double swap_edge_56_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
440 override;
441
448 virtual std::shared_ptr<SampleEnvelope> smoothing_containment_envelope(const size_t vid) const;
449 virtual std::shared_ptr<SampleEnvelope> smoothing_energy_envelope(const size_t vid) const = 0;
450
464 virtual std::shared_ptr<polysolve::nonlinear::Problem> smoothing_extra_energy(
465 const size_t /*vid*/) const
466 {
467 return nullptr;
468 }
469
470 bool smooth_before(const Tuple& t) override;
471 bool smooth_after(const Tuple& t) override;
472 void smooth_all_vertices(const size_t n_iters = 1);
476
477 bool invariants(const std::vector<Tuple>& t) override;
478
479protected:
482 virtual std::tuple<double, double> optimization_quality_stats();
483 virtual double optimization_stop_metric() const { return m_params.stop_energy; }
484 virtual size_t refine_sizing_around_worst(double max_metric) = 0;
485
508 virtual bool optimization_bare_coarsen_passes() const { return true; }
509 virtual void write_optimization_debug_output(const std::string& path) = 0;
510 virtual void optimization_sanity_checks_extra() {}
511
516 uint32_t m_op_epoch = 0;
517 virtual bool optimization_stop_at_float() const { return false; }
518
533 virtual bool optimization_stalled(double prev, double cur)
534 {
535 return (prev - cur) <= m_params.stuck_refine_stall_eps * (cur - optimization_stop_metric());
536 }
537
540 virtual bool collapse_before_vertex(size_t, size_t, double) { return true; }
541 virtual bool collapse_quality_allowed(size_t v1, double quality, double ring_max) const
542 {
543 return !m_vertex_attribute.at(v1).m_is_rounded || quality <= ring_max;
544 }
545 virtual bool collapse_is_order_2_edge(const std::array<size_t, 2>&) { return false; }
546 virtual bool
547 collapse_after_connectivity(size_t, size_t, const std::vector<std::array<size_t, 2>>&)
548 {
549 return true;
550 }
551 virtual void collapse_after_vertex(size_t, size_t) {}
552
554 virtual bool split_before_cells(const Tuple&, const std::vector<Tuple>&) { return true; }
556 virtual bool split_after_cells(size_t, size_t, size_t, const std::vector<Tuple>&)
557 {
558 return true;
559 }
562 virtual bool split_adjust_position(size_t, const std::vector<Tuple>&) { return true; }
564 virtual void split_after_vertex(size_t, bool) {}
565
566 virtual bool allow_surface_swap() const = 0;
567 virtual bool check_surface_topology() const = 0;
568
570 virtual bool swap_before_interior(const std::vector<size_t>&) { return true; }
571 virtual bool swap_before_surface(const std::vector<size_t>&, size_t, size_t, size_t, size_t)
572 {
573 return true;
574 }
576 virtual bool swap_after_cells(const std::vector<size_t>&, bool) { return true; }
577
578 // ---- SWAP REJECTION INSTRUMENTATION (debug; see swap_reject_report()) ----
579 // Every place a proposed swap can be turned down, counted. Added to find out why an offset
580 // surface flip is never accepted; the counters cost one relaxed atomic increment on a path
581 // that is already refusing the operation, and nothing reads them unless a caller asks.
582 //
583 // The refusals TetMesh makes itself, below every hook (the valence re-test, an open ring, a
584 // face or edge that already exists, no allowed 4-4 / 5-6 case beating the current cells, out
585 // of slots, a duplicate tet), were once visible here only as before_pass - after_enter. They
586 // are now reported one by one through TetMesh::op_event(); see op_accounting_report(). The
587 // per-turn line of this block still prints that difference as `connectivity`.
588 //
589 // Face swaps count their own reasons (face_*, and base_before / interior_hook / base_after /
590 // after_cells on their path) in the per-kind table alone -- swap_reject_kind_only() -- so
591 // swap_reject_report(), which has only ever described edge swaps, keeps meaning what it meant.
592 enum class SwapReject : int {
593 base_before, // TetMesh::swap_*_before said no
594 base_after, // TetMesh::swap_*_after said no
595 valence, // wrong incident-tet count for this swap kind
596 bbox, // edge on the bounding box
597 surface_not_allowed, // has surface faces and allow_surface_swap() is false
598 prepare_flip, // prepare_surface_flip() refused (see the flip_* reasons)
599 interior_hook, // swap_before_interior() refused
600 flip_open_boundary, // flipping would change the surface's boundary loops
601 flip_not_two_surf, // not exactly two incident surface faces
602 flip_nonmanifold_edge, // more than two incident surface faces
603 flip_cd_nonmanifold, // a surface face already sits on the new edge (c,d)
604 flip_new_face_surface, // (a,c,d) or (b,c,d) is already tagged surface
605 flip_app_refused, // swap_before_surface() refused (see the app_* reasons)
606 flip_wrong_case, // 4-4 / 5-6: the retetrahedralization is not the one that makes
607 // the surface diagonal (c,d), so this case is not the flip
608 app_capture_label, // application: the swap ring spans two construction labels
609 app_capture_tag, // application: the swap ring spans two cell tags
610 app_fid_missing, // application: a face of the pair could not be found
611 app_class_mismatch, // application: the two faces are different tracked surfaces
612 app_mask_mismatch, // application: the two faces carry different boundary masks
613 app_sag_raised, // application: the flip would raise the local sag
614 after_inverted, // a created cell is inverted
615 after_quality, // swap_quality_allowed() said no
616 after_cells, // swap_after_cells() refused (see the app_after_* reasons)
617 app_after_side_conflict, // application: two ring vertices of a new cell sit on two sides
618 app_after_no_side, // application: a new cell holds no ring vertex to take a side from
619 after_envelope, // a new surface triangle left the envelope
620 face_tracked_surface, // face swap: the face is a tracked surface face
621 face_tracked_bbox, // face swap: the face is on the bounding box
622 face_inverted, // face swap: one of the three new cells would be inverted
623 face_not_better, // face swap: a new cell is not strictly better than the two old ones
624 COUNT
625 };
629 enum class SwapStage : int {
630 attempt,
631 surface_attempt,
632 before_pass,
633 after_enter,
634 accepted,
635 COUNT
636 };
637
638 static const char* swap_reject_name(SwapReject r);
639 static const char* swap_stage_name(SwapStage s);
640 bool swap_reject(SwapReject r) const
641 {
642 m_swap_reject[size_t(r)].fetch_add(1, std::memory_order_relaxed);
643 return swap_reject_kind_only(r);
644 }
647 bool swap_reject_kind_only(SwapReject r) const
648 {
649 m_swap_reject_by_kind[size_t(current_op_kind())][size_t(r)].fetch_add(
650 1,
651 std::memory_order_relaxed);
652 return false;
653 }
654 void swap_stage(SwapStage s) const
655 {
656 m_swap_stage[size_t(s)].fetch_add(1, std::memory_order_relaxed);
657 }
658 void swap_counters_reset();
660 std::string swap_reject_report() const;
661
662 mutable std::array<std::atomic<long>, size_t(SwapReject::COUNT)> m_swap_reject{};
663 mutable std::array<std::atomic<long>, size_t(SwapStage::COUNT)> m_swap_stage{};
664
665 // ---- COLLAPSE REJECTION INSTRUMENTATION (see op_accounting_report()) ----
666 // Every place a collapse is turned down in a hook, counted once, at the place that decided.
667 // Before this, 85% of the collapse attempts on the deliverable cube (target_distance_rel 1e-2
668 // / front_conv_rel 1e-4, turn 5: 213k of 232k) were refused with nothing recorded but the
669 // ops guard's 367. What TetMesh refuses below the hooks (the link condition, a duplicate tet)
670 // arrives through op_event(). Before-hook reasons come first, after-hook reasons from
671 // after_base on.
672 enum class CollapseReject : int {
673 coarsen_length, // coarsening pass only: the edge is at or above the collapse target
674 bbox, // v1 sits on a bounding-box face that v2 does not
675 surface_leaves_envelope, // v1 on the surface, v2 not, and v2 not inside the envelope
676 inverted, // a cell the collapse reshapes would invert
677 quality, // collapse_quality_allowed() said no
678 substructure_link, // preserve_topology, both ends on the surface: substructure link
679 app_both_surfaces, // application: an end on the input complex and an end on the offset
680 app_front_unlimited, // application: an unlimited-length pass may not remove a front vertex
681 app_leaves_input, // application: v1 on the input complex, v2 not
682 app_leaves_offset, // application: v1 on the offset surface, v2 not
683 app_leaves_region, // application: v1 on a region boundary, v2 not
684 app_order2, // application: an order-2 vertex would merge into a lower-order one
685 app_substructure_link, // application: the substructure link condition, unconditional
686 app_ops_guard, // application: the ops divergence guard
687 after_base, // TetMesh::collapse_edge_after said no
688 after_connectivity, // collapse_after_connectivity() said no
689 after_envelope, // a surface face the survivor keeps left the envelope
690 after_face_attribute, // a face attribute found no face left to land on
691 after_coarsen_region, // coarsening only: the region's worst quality rose
692 COUNT
693 };
694 static const char* collapse_reject_name(CollapseReject r);
695 bool collapse_reject(CollapseReject r) const
696 {
697 m_collapse_reject[size_t(r)].fetch_add(1, std::memory_order_relaxed);
698 return false;
699 }
700 mutable std::array<std::atomic<long>, size_t(CollapseReject::COUNT)> m_collapse_reject{};
701
702 // ---- OPERATION ACCOUNTING (counting only) ----
703 // TetMesh reports every operation's attempt and its one outcome through op_event(); this
704 // counts them per kind. op_accounting_report() then checks, per kind, that the outcomes add
705 // up to the attempts, and that the before- and after-hook refusals add up to the reasons the
706 // hooks counted (SwapReject / CollapseReject). A nonzero remainder is a refusal nobody named.
707 void op_event(OpKind k, OpEvent e) const override
708 {
709 if (e == OpEvent::attempt) current_op_kind() = k;
710 m_op_events[size_t(k)][size_t(e)].fetch_add(1, std::memory_order_relaxed);
711 }
715 static OpKind& current_op_kind()
716 {
717 static thread_local OpKind k = OpKind::COUNT;
718 return k;
719 }
722 std::string op_accounting_report(OpKind k) const;
724 bool op_accounting_unexplained(OpKind k) const;
725 void op_accounting_reset();
726 static const char* op_kind_name(OpKind k);
727 static const char* op_event_name(OpEvent e);
728
735 enum class SwapRejectRole { before_leaf, after_leaf, wrapper, per_case };
736 static SwapRejectRole swap_reject_role(SwapReject r);
739 {
740 std::string before, after;
741 long before_sum = 0, after_sum = 0;
742 bool counted = true; // false: this kind's hooks count no reasons (split)
743 };
744 OpHookReasons op_hook_reasons(OpKind k) const;
745 long op_event_count(const OpKind k, const OpEvent e) const
746 {
747 return m_op_events[size_t(k)][size_t(e)].load(std::memory_order_relaxed);
748 }
750 long op_unaccounted(OpKind k) const;
751
752 mutable std::array<std::array<std::atomic<long>, size_t(OpEvent::COUNT)>, size_t(OpKind::COUNT)>
753 m_op_events{};
754 mutable std::
755 array<std::array<std::atomic<long>, size_t(SwapReject::COUNT)>, size_t(OpKind::COUNT) + 1>
756 m_swap_reject_by_kind{};
757
770 virtual bool swap_quality_allowed(double after, double before, bool /*is_surface_flip*/) const
771 {
772 return after < before;
773 }
774
776 {
777 double max_energy;
778 std::map<std::array<size_t, 3>, FaceAttributes> changed_faces;
779
780 bool is_surface_flip = false;
781 size_t sf_a = 0, sf_b = 0, sf_c = 0, sf_d = 0;
782 FaceAttributes sf_face_attr;
783 };
785
787 {
788 size_t v1_id = 0;
789 size_t v2_id = 0;
790 bool is_edge_on_surface = false;
791 bool is_edge_open_boundary = false;
792 size_t edge_order = 0;
793 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
794 };
796
798 {
799 size_t v1_id = 0;
800 size_t v2_id = 0;
801 double max_energy = 0.;
802 double edge_length = 0.;
803 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
804 std::vector<std::array<size_t, 3>> surface_faces;
805 std::vector<std::array<size_t, 2>> boundary_edges;
806 std::vector<size_t> changed_tids;
807 std::vector<double> changed_energies;
811 };
813
815 bool m_coarsen_mode = false;
816
817private:
827 {
828 std::vector<size_t> ring; // vertices to re-smooth, BFS order
829 std::vector<size_t> frontier;
830 std::vector<size_t> next;
831 std::vector<size_t> one_ring;
832 std::vector<uint32_t> stamp;
833 uint32_t epoch = 0;
834 VertexAttributes saved_vertex;
835 std::vector<std::pair<size_t, double>> saved_qualities;
836 };
838
840 const std::vector<size_t>&
841 collect_vertex_ball(const size_t* seeds, size_t n_seeds, int n, CoarsenScratch& scr) const;
842
845 double region_max_quality_rel(const std::vector<size_t>& vids) const;
846
848 bool smooth_vertex_reversible(size_t vid, CoarsenScratch& scr);
849
856 bool is_limit_length,
857 int lock_ring,
858 size_t max_passes = 0,
859 bool exact_ball_lock = false);
860};
861
862} // 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
a Tuple refers to a global vid and a global tet id, and a local edge id and local face id
Definition TetMesh.h:50
Definition TetMesh.h:25
Tuple tuple_from_vertex(size_t vid) const
get a Tuple from global vertex index
Definition TetMesh.cpp:592
What tetwild and simwild's 3D mesh share.
Definition TetOptimizerMesh.h:46
bool m_collapse_limit_length
Definition TetOptimizerMesh.h:148
std::string op_accounting_report(OpKind k) const
Definition TetOptimizerMesh.cpp:867
void gradation_smooth_sizing(double grade, const std::vector< size_t > &seeds)
Grade the refined sizing region into its surroundings (monotone, only lowers).
Definition TetOptimizerMesh.cpp:432
virtual std::shared_ptr< SampleEnvelope > surface_envelope_for_face(const std::array< size_t, 3 > &vids) const
Envelope the tracked-surface triangle vids must stay inside.
Definition TetOptimizerMesh.h:308
double swap_edge_44_energy(const std::vector< std::array< size_t, 4 > > &tets, const int op_case) override
User specified energy to decide which of the 4 possible orientations should be chosen.
Definition TetOptimizerMesh.cpp:297
optimization::NewtonCounters m_newton
Definition TetOptimizerMesh.h:144
bool swap_edge_44_before(const Tuple &t) override
User specified preparations and desideratas for an 4-4 edge swap before changing the connectivity.
Definition TetOptimizerMeshSwaps.cpp:631
size_t m_force_split_count
Force-splits taken in the current split pass. Diagnostic only.
Definition TetOptimizerMesh.h:155
AttributeContainerGroup m_vertex_attr_group
What p_vertex_attrs points at, so a derived class can register more.
Definition TetOptimizerMesh.h:93
bool vertex_is_on_surface(const size_t vid) const override
Is a vertex part of the substructure.
Definition TetOptimizerMesh.cpp:734
SwapStage
Definition TetOptimizerMesh.h:629
bool collapse_edge_after(const Tuple &t) override
User specified modifications and desideratas for after an edge collapse.
Definition TetOptimizerMeshCollapse.cpp:328
SwapRejectRole
Definition TetOptimizerMesh.h:735
std::unique_ptr< std::atomic< int >[]> m_high_valence_claim
Per-pass claims for the shared high-valence split gate.
Definition TetOptimizerMesh.h:163
std::vector< size_t > all_vertex_ids() const override
Every live vertex, in the mesh's own iteration order.
Definition TetOptimizerMesh.cpp:421
double region_max_quality_rel(const std::vector< size_t > &vids) const
Definition TetOptimizerMeshCollapse.cpp:546
bool m_coarsen_mode
Set for the duration of coarsen_mesh(); read-only while a pass is running.
Definition TetOptimizerMesh.h:815
bool swap_face_after(const Tuple &t) override
User specified modifications and desideratas for after a 2-3 face swap.
Definition TetOptimizerMeshSwaps.cpp:530
virtual void update_attributes()
Update the attributes of the mesh after an iteration of operations.
Definition TetOptimizerMesh.h:237
bool swap_edge_44_after(const Tuple &t) override
User specified modifications and desideratas for after a 4-4 edge swap.
Definition TetOptimizerMeshSwaps.cpp:675
bool swap_edge_before(const Tuple &t) override
User specified preparations and desideratas for an 3-2 edge swap before changing the conenctivity.
Definition TetOptimizerMeshSwaps.cpp:115
bool swap_face_before(const Tuple &t) override
User specified preparations and desideratas for an 2-3 face swap befroe changing the geometry.
Definition TetOptimizerMeshSwaps.cpp:468
virtual void split_after_vertex(size_t, bool)
Application metadata not represented by the shared vertex attributes.
Definition TetOptimizerMesh.h:564
bool surface_triangle_is_outside(const size_t a, const size_t b, const size_t c) const
Definition TetOptimizerMesh.h:316
bool swap_edge_56_after(const Tuple &t) override
User specified modifications and desideratas for after a 5-6 edge swap.
Definition TetOptimizerMeshSwaps.cpp:804
virtual bool split_after_cells(size_t, size_t, size_t, const std::vector< Tuple > &)
Restore application cell data on the children made by a split.
Definition TetOptimizerMesh.h:556
virtual double cell_quality(const size_t tid) const =0
The quality of cell tid, and how to write it.
virtual std::shared_ptr< polysolve::nonlinear::Problem > smoothing_extra_energy(const size_t) const
An extra term the application adds to this vertex's smoothing objective, or null.
Definition TetOptimizerMesh.h:464
virtual bool collapse_before_vertex(size_t, size_t, double)
Definition TetOptimizerMesh.h:540
virtual std::vector< size_t > active_vertices() const
Definition TetOptimizerMesh.cpp:496
wmtk::threading::enumerable_thread_specific< std::unique_ptr< polysolve::nonlinear::Solver > > m_solver
Per-thread Newton solver for smoothing; created on first use.
Definition TetOptimizerMesh.h:137
size_t get_order_of_vertex(const size_t vid) const override
Get the order of a vertex.
Definition TetOptimizerMesh.cpp:744
std::string m_debug_pass_name
Definition TetOptimizerMesh.h:247
double swap_edge_56_energy(const std::vector< std::array< size_t, 4 > > &tets, const int op_case) override
User specified energy to decide which of the 5 possible orientations should be chosen.
Definition TetOptimizerMesh.cpp:312
std::string swap_reject_report() const
One line per nonzero counter, for a per-turn log. Does not reset.
Definition TetOptimizerMeshSwaps.cpp:214
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 TetOptimizerMesh.h:533
bool collapse_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge collapse before changing the connectivity.
Definition TetOptimizerMeshCollapse.cpp:97
virtual bool is_open_boundary_edge(const Tuple &e)
Whether edge e lies on the boundary of the tracked surface.
Definition TetOptimizerMesh.h:286
int m_iterations_used
Shared TetWild/SimWild outer optimization schedule.
Definition TetOptimizerMesh.h:240
virtual void log_smoothing_pass_accounting()
Definition TetOptimizerMesh.h:475
bool is_inverted_f(const Tuple &loc) const
Inversion check using only the double positions.
Definition TetOptimizerMesh.cpp:508
virtual bool swap_after_cells(const std::vector< size_t > &, bool)
Propagate application data to the cells made by a successful topological swap.
Definition TetOptimizerMesh.h:576
virtual double quality_rel(const size_t tid) const
A cell's quality relative to the quality it is required to reach; <= 1 means it meets it.
Definition TetOptimizerMesh.h:205
virtual bool optimization_bare_coarsen_passes() const
Whether the loop opens with an UNLIMITED-LENGTH collapse pass.
Definition TetOptimizerMesh.h:508
AttributeContainerGroup m_face_attr_group
What p_face_attrs points at, so a derived class can register more.
Definition TetOptimizerMesh.h:108
virtual bool split_adjust_position(size_t, const std::vector< Tuple > &)
Definition TetOptimizerMesh.h:562
int edge_incident_surface_face_count(const Tuple &e)
How many of the faces incident to edge e are on the tracked surface.
Definition TetOptimizerMesh.cpp:681
bool round_vertex(const size_t vid) override
Definition TetOptimizerMesh.h:270
uint32_t m_op_epoch
Definition TetOptimizerMesh.h:516
bool swap_edge_56_before(const Tuple &t) override
User specified preparations and desideratas for a 5-6 edge swap before changing the connectivity.
Definition TetOptimizerMeshSwaps.cpp:761
static constexpr double MAX_ENERGY
The sentinel get_quality returns for an element AMIPS cannot score.
Definition TetOptimizerMesh.h:118
virtual std::shared_ptr< SampleEnvelope > smoothing_containment_envelope(const size_t vid) const
Envelope the resulting surface triangles are checked against.
Definition TetOptimizerMesh.cpp:414
bool split_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge split before changing the connectivity.
Definition TetOptimizerMeshSplit.cpp:94
bool swap_edge_after(const Tuple &t) override
User specified modifications and desideratas for after a 3-2 edge swap.
Definition TetOptimizerMeshSwaps.cpp:369
std::set< simplex::Edge > m_force_split_edges
Definition TetOptimizerMesh.h:153
bool swap_reject_kind_only(SwapReject r) const
Definition TetOptimizerMesh.h:647
bool smooth_before(const Tuple &t) override
User specified preparations and desideratas for smoothing a vertex.
Definition TetOptimizerMesh.cpp:327
optimization::SmoothRejectCounters m_smooth_rejects
Why smoothing attempts were refused, reported once per pass.
Definition TetOptimizerMesh.h:140
static OpKind & current_op_kind()
Definition TetOptimizerMesh.h:715
size_t collapse_all_edges_impl(bool is_limit_length, int lock_ring, size_t max_passes=0, bool exact_ball_lock=false)
Definition TetOptimizerMeshCollapse.cpp:24
size_t coarsen_mesh()
Coarsen the mesh without letting the max energy rise.
Definition TetOptimizerMeshCollapse.cpp:598
bool round(const Tuple &v)
Round a vertex position to floating point, if that inverts no incident tet.
Definition TetOptimizerMesh.cpp:576
bool op_accounting_unexplained(OpKind k) const
True when the report for k has a nonzero remainder: a refusal no counter named.
Definition TetOptimizerMesh.cpp:858
bool smooth_vertex_reversible(size_t vid, CoarsenScratch &scr)
One smoothing attempt on vid, restoring everything it wrote if it is rejected.
Definition TetOptimizerMeshCollapse.cpp:557
virtual std::tuple< double, double > optimization_quality_stats()
Definition TetOptimizerMesh.cpp:28
bool coarsen_collapse_edge(const Tuple &e, std::vector< Tuple > &new_tets)
One collapse under the coarsening rules, outside a coarsening pass.
Definition TetOptimizerMeshCollapse.cpp:586
double m_s_amips
Definition TetOptimizerMesh.h:129
double active_quality_threshold() const
Cell-quality threshold above which a tet is "active" (worth operating on) for the skip-good-regions f...
Definition TetOptimizerMesh.h:344
virtual bool split_before_cells(const Tuple &, const std::vector< Tuple > &)
Cache application cell data before a split. TetWild needs none; SimWild caches tags.
Definition TetOptimizerMesh.h:554
long op_unaccounted(OpKind k) const
Attempts minus every outcome: 0 unless an exit of the TetMesh operation reports nothing.
Definition TetOptimizerMesh.cpp:814
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 TetOptimizerMeshCollapse.cpp:485
virtual bool swap_quality_allowed(double after, double before, bool) const
Definition TetOptimizerMesh.h:770
virtual bool swap_before_interior(const std::vector< size_t > &)
Application data attached to the old cells. TetWild has none; SimWild caches tags.
Definition TetOptimizerMesh.h:570
OptimizerParameters & m_params
Definition TetOptimizerMesh.h:122
bool swap_edge_56_accept_case(const std::array< size_t, 3 > &new_face) override
Filter which of the 5-6 orientations may be chosen.
Definition TetOptimizerMeshSwaps.cpp:349
std::shared_ptr< SampleEnvelope > m_envelope
Surface envelope: what a surface vertex is pulled toward and checked against.
Definition TetOptimizerMesh.h:125
bool split_edge_after(const Tuple &loc) override
This function computes the attributes for the added simplices. User specified modifications and desid...
Definition TetOptimizerMeshSplit.cpp:182
bool vertex_is_rounded(const size_t vid) const override
Whether this vertex's double position is currently trusted.
Definition TetOptimizerMesh.h:263
bool face_is_on_surface(const size_t fid) const override
Is a face part of the substructure.
Definition TetOptimizerMesh.cpp:739
bool swap_edge_44_accept_case(const std::array< size_t, 2 > &new_edge) override
Filter which of the 4-4 orientations may be chosen.
Definition TetOptimizerMeshSwaps.cpp:339
bool smooth_after(const Tuple &t) override
User specified modifications and desideratas for after smoothing a vertex.
Definition TetOptimizerMesh.cpp:341
Definition Simplex.hpp:46
Definition enumerable_thread_specific.hpp:26
Definition AttributeCollection.hpp:36
The parameters tetwild, triwild and simwild all share.
Definition OptimizerParameters.h:29
Per-thread buffers for the coarsening composite, so it allocates nothing.
Definition TetOptimizerMesh.h:827
What coarsen_mesh() achieved, for the run report. Zeroed when the pass is off.
Definition TetOptimizerMesh.h:387
Definition TetOptimizerMesh.h:798
double region_max_rel_before
Definition TetOptimizerMesh.h:810
A kind's hook refusals by reason: the nonzero leaves as "name=n" and their sums.
Definition TetOptimizerMesh.h:739
Definition TetOptimizerMesh.h:787
Definition TetOptimizerMesh.h:776
Definition TetOptimizerMesh.h:49
size_t partition_id
Required for multi-threading.
Definition TetOptimizerMesh.h:73
size_t m_order
Definition TetOptimizerMesh.h:67
bool m_is_rounded
Definition TetOptimizerMesh.h:57
How the vertex solves of a smoothing pass ended: Newton iterations taken and the status polysolve sto...
Definition SmoothVertex.hpp:75
Why a smoothing attempt was refused, counted per pass.
Definition SmoothVertex.hpp:31
A topological fingerprint of a tracked surface inside a tet mesh.
Definition SurfaceTopology.hpp:23