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/ExactPosition.hpp>
8#include <wmtk/Types.hpp>
9#include <wmtk/envelope/Envelope.hpp>
10#include <wmtk/history/History.hpp>
11#include <wmtk/history/VolumeHistory.hpp>
12#include <wmtk/optimization/SmoothVertex.hpp>
13#include <wmtk/optimization/solver.hpp>
14#include <wmtk/simplex/Simplex.hpp>
15#include <wmtk/threading/enumerable_thread_specific.hpp>
16#include <wmtk/utils/SurfaceTopology.hpp>
17
18#include <igl/Timer.h>
19
20#include <array>
21#include <atomic>
22#include <cmath>
23#include <functional>
24#include <limits>
25#include <map>
26#include <memory>
27#include <optional>
28#include <set>
29#include <vector>
30
31namespace wmtk {
32
51{
52public:
54 {
55 Vector3d m_posf; // position as double
61 bool m_is_rounded = false;
62
63 bool m_is_on_surface = false;
71 size_t m_order = 0;
72 std::vector<int> on_bbox_faces;
73
74 double m_sizing_scalar = 1;
75
77 size_t partition_id = 0;
78
88 Vector3r pos() const { return m_exact.value(m_posf); }
89 bool pos_coord_equals(int k, const Rational& r) const
90 {
91 return m_exact.coord_equals(k, m_posf, r);
92 }
93 void set_pos(const Vector3r& p) { m_exact.store(p); }
94 void set_pos_to_posf() { m_exact.clear(); }
95 ExactPosition<Vector3r, Vector3d> m_exact;
98 VertexAttributes() {}
99 VertexAttributes(const Vector3r& p);
100 };
101
102 using FaceAttributes = wmtk::SurfaceTagAttributes;
103
104 using VertAttCol = AttributeCollection<VertexAttributes>;
105 using FaceAttCol = AttributeCollection<FaceAttributes>;
106
107 VertAttCol m_vertex_attribute;
108 FaceAttCol m_face_attribute;
109
120
130 std::atomic<size_t> m_inconsistent_orientation_flips = 0;
131
137 std::vector<std::array<size_t, 3>> oriented_tracked_faces() const;
138
150 std::vector<std::pair<std::array<size_t, 2>, int>> tracked_surface_boundary() const;
151
159
174
214 void throw_if_in_operation_pass(const char* call) const
215 {
217 log_and_throw_error(
218 "{}() called while an operation pass runs; call it before or after the pass.",
219 call);
220 }
221 }
236 {
237 throw_if_in_operation_pass("add_edge_attributes");
238 m_edge_attr_group.add(c);
239 p_edge_attrs = &m_edge_attr_group;
240 c->resize(6 * tet_storage_capacity());
241 }
242
256 {
257 bool m_is_feature_edge = false;
258 };
259 using EdgeAttCol = AttributeCollection<FeatureEdgeAttributes>;
262
271
280 std::shared_ptr<Envelope> m_feature_envelope;
281
295 {
296 throw_if_in_operation_pass("enable_feature_edge_tracking");
297 if (m_track_feature_edges) return;
300 }
301
304 bool vertex_has_feature_edge(size_t vid) const;
305
306 // Substructure widening for the link condition (preserve_topology): a tagged feature
307 // edge is order-2 substructure, a vertex with two incident tagged edges is on a curve
308 // (order 2), with one or three-plus it is a curve endpoint or junction (order 3). The
309 // meaning of get_order_of_* is untouched.
310 size_t substructure_order_of_edge(const std::array<size_t, 2>& vids) const override;
311 size_t substructure_order_of_vertex(size_t vid) const override;
312 void substructure_feature_neighbors(size_t vid, std::vector<size_t>& out) const override;
316 bool feature_edges_at_vertex_inside(size_t vid) const;
317
342 static constexpr size_t NO_FEATURE_POINT = std::numeric_limits<size_t>::max();
348 using FeaturePointAttCol = AttributeCollection<FeaturePointAttributes>;
354 std::vector<Vector3d> m_feature_points;
357 double m_feature_eps = -1;
362
376 void enable_feature_point_tracking(const bool preserve)
377 {
378 throw_if_in_operation_pass("enable_feature_point_tracking");
381 m_feature_point_attribute.resize(vert_storage_capacity());
382 }
384 m_preserve_feature_points = preserve;
385 }
386
393 bool collapse_breaks_feature_point(const size_t v1_id, const size_t v2_id) const;
394
397 bool feature_point_ball_contains(const size_t vid, const Vector3d& p) const;
398
401 std::pair<size_t, size_t> feature_retention(double* worst_ratio = nullptr) const;
408 virtual bool smoothing_position_is_allowed(const size_t vid, const Vector3d& p) const
409 {
410 return feature_point_ball_contains(vid, p);
411 }
412
421 static constexpr double MAX_ENERGY = 1e50;
422
426
428 std::shared_ptr<Envelope> m_envelope;
429
432 double m_s_amips = 1.;
433 double m_s_envelope = -1.;
434
435 double time_env = 0.0;
436 igl::Timer isout_timer;
437
441
448
452
456 std::set<simplex::Edge> m_force_split_edges;
459
460 bool is_force_split_edge(const size_t v1, const size_t v2) const
461 {
462 return m_force_split_edges.find(simplex::Edge(v1, v2)) != m_force_split_edges.end();
463 }
464
466 std::unique_ptr<std::atomic<int>[]> m_high_valence_claim;
467 size_t m_high_valence_claim_size = 0;
468 std::atomic<size_t> m_high_valence_rejects = 0;
469
473 bool storage_grows_on_demand() const override { return true; }
474
475protected:
479 void on_slot_storage_grown() override
480 {
481 if (!m_high_valence_claim) return;
482 const size_t n = std::max(vert_capacity(), m_vertex_attribute.size());
483 if (n <= m_high_valence_claim_size) return;
484 auto grown = std::make_unique<std::atomic<int>[]>(n);
485 for (size_t i = 0; i < m_high_valence_claim_size; ++i) {
486 grown[i].store(m_high_valence_claim[i].load(std::memory_order_relaxed));
487 }
488 m_high_valence_claim = std::move(grown);
489 m_high_valence_claim_size = n;
490 }
491
492public:
495 bool split_edge_is_due(const Tuple& e) const;
498 size_t m_split_order_wait_defects = 0;
499
500 explicit TetOptimizerMesh(OptimizerParameters& params, std::shared_ptr<Envelope> env)
501 : m_params(params)
502 , m_envelope(std::move(env))
503 {
504 m_vertex_attr_group.add(&m_vertex_attribute);
505 p_vertex_attrs = &m_vertex_attr_group;
506 m_face_attr_group.add(&m_face_attribute);
507 p_face_attrs = &m_face_attr_group;
508 }
509 ~TetOptimizerMesh() override = default;
510
519 virtual double cell_quality(const size_t tid) const = 0;
520 virtual void set_cell_quality(const size_t tid, const double q) = 0;
521
538 virtual double quality_rel(const size_t tid) const
539 {
540 return std::cbrt(cell_quality(tid)) / m_params.stop_energy;
541 }
542
543 // TODO This should not be here but inside wmtk
544 void compute_vertex_partition();
545 void compute_vertex_partition_morton();
546
547 size_t get_partition_id(const Tuple& loc) const
548 {
549 return m_vertex_attribute[loc.vid(*this)].partition_id;
550 }
551
552 double get_length2(const Tuple& l) const;
553
554 bool is_inverted(const std::array<size_t, 4>& vs) const;
555 bool is_inverted(const Tuple& loc) const;
557 bool is_inverted_f(const Tuple& loc) const;
558
559 double get_quality(const std::array<size_t, 4>& vs) const;
560 double get_quality(const Tuple& loc) const;
561 std::tuple<double, double> get_max_avg_energy();
562
570 virtual void update_attributes() {}
573
576 void record_surface_history(const std::string& metadata);
587 std::optional<history::SurfaceHistory> finish_surface_history(
588 const history::SurfaceHistory* input = nullptr);
589
597 std::optional<std::vector<uint8_t>> finish_volume_history(
598 const std::map<int64_t, std::string>& tag_names = {});
599
601 using PositionKey = std::array<std::array<double, 3>, 3>;
602 static PositionKey position_key(const Vector3d& a, const Vector3d& b, const Vector3d& c);
606 std::vector<std::pair<PositionKey, std::vector<uint32_t>>> m_insertion_sources;
610 std::shared_ptr<history::VolumeRecorder> m_recorded_volume;
611 uint64_t m_surface_edit_offset = 0;
612 std::optional<history::SurfaceKey> m_finished_surface;
613
615 bool is_tracked_face(size_t tid, int j) const override;
619 std::array<size_t, 3> orient_tracked_face(
620 const std::array<size_t, 3>& f,
621 const std::vector<size_t>& tets) const override;
623 std::vector<std::array<size_t, 2>> tracked_feature_edges() const override;
624
626 bool checks_tracked_surface() const override { return m_params.check_surface_folds; }
627 void tracked_surface_before(const std::vector<size_t>& vs, bool all) override;
628 bool tracked_surface_after(const std::vector<size_t>& vs, bool all) override;
630 std::atomic<size_t> m_surface_fold_refusals = 0;
631
634 std::shared_ptr<history::TrackedSurfaceRecorder> m_recorded_surface;
639 {
640 bool skip = true;
641 Eigen::Vector3d normal = Eigen::Vector3d::Zero();
642 size_t against = 0;
643 size_t star_folds = 0;
644 };
648 Eigen::Vector3d tracked_area_normal(const std::vector<std::array<size_t, 3>>& faces) const;
649 size_t tracked_not_facing(
650 const std::vector<std::array<size_t, 3>>& faces,
651 const Eigen::Vector3d& n) const;
652 size_t tracked_star_folds(const std::vector<std::array<size_t, 3>>& faces) const;
654 std::vector<std::vector<uint64_t>> m_recorded_sources;
655 int m_debug_print_counter = 0;
661 std::string m_debug_pass_name;
662 void mesh_improvement(int max_its = 80);
663 std::tuple<double, double> local_operations(
664 const std::array<int, 4>& ops,
665 bool collapse_limit_length = true);
666
671 bool round(const Tuple& v);
672
673protected:
674 // RationalPositions supplies round_all_vertices() and round_and_check_all_rounded() on
675 // top of these three.
676 std::vector<size_t> all_vertex_ids() const override;
677 bool vertex_is_rounded(const size_t vid) const override
678 {
679 return m_vertex_attribute.at(vid).m_is_rounded;
680 }
681 // Equivalent to round() on the tuple get_vertices() would have yielded: round() reads only
682 // the vid and the one-ring, and the one-ring query is answered from
683 // m_vertex_connectivity[vid] regardless of which cell the tuple names.
684 bool round_vertex(const size_t vid) override { return round(tuple_from_vertex(vid)); }
685
686public:
687 bool is_edge_on_surface(const Tuple& loc);
688 bool is_edge_on_bbox(const Tuple& loc);
700 virtual bool is_open_boundary_edge(const Tuple& e) { return false; }
707 int edge_incident_surface_face_count(const Tuple& e);
708
729 virtual std::shared_ptr<Envelope> surface_envelope_for_face(
730 const std::array<size_t, 3>& vids,
731 const FaceAttributes& attr) const
732 {
733 return m_envelope;
734 }
735
740 const size_t a,
741 const size_t b,
742 const size_t c,
743 const FaceAttributes& attr) const
744 {
745 const std::shared_ptr<Envelope> env = surface_envelope_for_face({{a, b, c}}, attr);
746 if (!env) return false;
747 const auto& VA = m_vertex_attribute;
748 return env->is_outside({{VA[a].m_posf, VA[b].m_posf, VA[c].m_posf}});
749 }
750
751 bool vertex_is_on_surface(const size_t vid) const override;
752 bool face_is_on_surface(const size_t fid) const override;
753 size_t get_order_of_vertex(const size_t vid) const override;
754
755 std::vector<std::array<size_t, 3>> get_faces_by_condition(
756 std::function<bool(const FaceAttributes&)> cond) const;
757
758 void output_faces(std::string file, std::function<bool(const FaceAttributes&)> cond);
759
761 void gradation_smooth_sizing(double grade, const std::vector<size_t>& seeds);
762
772 {
773 const double e = m_params.skip_good_regions_margin * m_params.stop_energy;
774 return e * e * e;
775 }
776
779 virtual std::vector<size_t> active_vertices() const;
780
781 // TetWild's split engine. SimWild inherits it and customizes only application data,
782 // annotation-only placement, and order-2 metadata through the hooks below.
783 void split_all_edges();
784 bool split_edge_before(const Tuple& t) override;
785 bool split_edge_after(const Tuple& loc) override;
786
787 // TetWild's collapse engine. SimWild customizes only application policy/metadata.
788 void collapse_all_edges(bool is_limit_length = true);
789 bool collapse_edge_before(const Tuple& t) override;
790 bool collapse_edge_after(const Tuple& t) override;
791
801 size_t coarsen_mesh();
802
810 bool coarsen_collapse_edge(const Tuple& e, std::vector<Tuple>& new_tets);
811
814 {
815 size_t accepted = 0;
816 size_t cells_before = 0;
817 size_t cells_after = 0;
818 double max_energy_before = 0.;
819 double max_energy_after = 0.;
820 };
821 CoarsenStats m_coarsen_stats;
822
823 // TetWild's complete swap engine. SimWild inherits these operations and customizes only
824 // the tag bookkeeping through the hooks below.
825 size_t swap_all_edges_32();
826 bool swap_edge_before(const Tuple& t) override;
827 bool swap_edge_after(const Tuple& t) override;
828
829 size_t swap_all_edges_44();
830 bool swap_edge_44_before(const Tuple& t) override;
831 bool swap_edge_44_accept_case(const std::array<size_t, 2>& new_edge) override;
832 bool swap_edge_44_after(const Tuple& t) override;
833
834 size_t swap_all_edges_56();
835 bool swap_edge_56_before(const Tuple& t) override;
836 bool swap_edge_56_accept_case(const std::array<size_t, 3>& new_face) override;
837 bool swap_edge_56_after(const Tuple& t) override;
838
839 size_t swap_all_faces();
840 bool swap_face_before(const Tuple& t) override;
841 bool swap_face_after(const Tuple& t) override;
842 size_t swap_all_edges_all();
843
844 bool prepare_surface_flip(const Tuple& t, const std::vector<size_t>& incident_tets);
845
847 SurfaceTopoSignature surface_topology_signature() const
848 {
849 return wmtk::utils::surface_topology_signature(*this, [this](size_t fid) {
850 return m_face_attribute[fid].m_is_surface_fs;
851 });
852 }
853 void warn_if_surface_topology_changed(const SurfaceTopoSignature& before, const char* where)
854 const
855 {
856 wmtk::utils::warn_if_surface_topology_changed(before, surface_topology_signature(), where);
857 }
858
859 // Operation diagnostics shared by TetWild and SimWild.
860 std::atomic<int> cnt_swap = 0;
861 std::atomic<int> cnt_surface_swap = 0;
862 std::atomic<int> cnt_surface_swap_32 = 0, cnt_surface_swap_44 = 0, cnt_surface_swap_56 = 0;
863
864 double swap_edge_44_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
865 override;
866 double swap_edge_56_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
867 override;
868
883 virtual std::shared_ptr<Envelope> smoothing_containment_envelope(
884 const size_t /*vid*/,
885 const std::array<size_t, 3>& face,
886 const FaceAttributes& attr) const
887 {
888 return surface_envelope_for_face(face, attr);
889 }
895 virtual std::shared_ptr<Envelope> smoothing_energy_envelope(const size_t vid) const = 0;
896
901 virtual bool boundary_edges_at_vertex_inside(size_t) const { return true; }
902
916 virtual std::shared_ptr<polysolve::nonlinear::Problem> smoothing_extra_energy(
917 const size_t /*vid*/) const
918 {
919 return nullptr;
920 }
921
932 virtual double smoothing_cell_energy(const size_t /*tid*/, const double quality) const
933 {
934 return quality;
935 }
936
951 virtual double smoothing_ring_energy(const std::vector<Tuple>& ring, const bool stored) const
952 {
953 double m = 0.;
954 for (const Tuple& loc : ring) {
955 const size_t tid = loc.tid(*this);
956 m = std::max(
957 m,
958 smoothing_cell_energy(tid, stored ? cell_quality(tid) : get_quality(loc)));
959 }
960 return m;
961 }
962
975 bool smooth_before(const Tuple& t) override;
976 bool smooth_after(const Tuple& t) override;
977 void smooth_all_vertices(const size_t n_iters = 1);
979 bool use_colored_smoothing() const;
981 void smooth_vertices_colored(const std::vector<std::pair<std::string, Tuple>>& ops);
989 virtual void smoothing_pass_done() {}
990
991 bool invariants(const std::vector<Tuple>& t) override;
992
993protected:
996 virtual std::tuple<double, double> optimization_quality_stats();
997 virtual double optimization_stop_metric() const { return m_params.stop_energy; }
998 virtual size_t refine_sizing_around_worst(double max_metric) = 0;
999
1022 virtual bool optimization_bare_coarsen_passes() const { return true; }
1025 virtual void optimization_iteration_done(int /*it*/) {}
1026 virtual void write_optimization_debug_output(const std::string& path) = 0;
1027 virtual void optimization_sanity_checks_extra() {}
1028
1033 uint32_t m_op_epoch = 0;
1034 virtual bool optimization_stop_at_float() const { return false; }
1035
1050 virtual bool optimization_stalled(double prev, double cur)
1051 {
1052 return (prev - cur) <= m_params.stuck_refine_stall_eps * (cur - optimization_stop_metric());
1053 }
1054
1057 virtual bool collapse_before_vertex(size_t, size_t, double) { return true; }
1058 virtual bool collapse_quality_allowed(size_t v1, double quality, double ring_max) const
1059 {
1060 return !m_vertex_attribute.at(v1).m_is_rounded || quality <= ring_max;
1061 }
1062 virtual bool collapse_is_order_2_edge(const std::array<size_t, 2>&) { return false; }
1063 virtual bool
1064 collapse_after_connectivity(size_t, size_t, const std::vector<std::array<size_t, 2>>&)
1065 {
1066 return true;
1067 }
1068 virtual void collapse_after_vertex(size_t, size_t) {}
1071 virtual void collapse_after_features(size_t, size_t) {}
1072
1074 virtual bool split_before_cells(const Tuple&, const std::vector<Tuple>&) { return true; }
1076 virtual bool split_after_cells(size_t, size_t, size_t, const std::vector<Tuple>&)
1077 {
1078 return true;
1079 }
1082 virtual bool split_adjust_position(size_t, const std::vector<Tuple>&) { return true; }
1084 virtual void split_after_vertex(size_t, bool) {}
1085
1086 virtual bool allow_surface_swap() const = 0;
1087 virtual bool check_surface_topology() const = 0;
1088
1090 virtual bool swap_before_interior(const std::vector<size_t>&) { return true; }
1091 virtual bool swap_before_surface(const std::vector<size_t>&, size_t, size_t, size_t, size_t)
1092 {
1093 return true;
1094 }
1096 virtual bool swap_after_cells(const std::vector<size_t>&, bool) { return true; }
1097
1098 // ---- SWAP REJECTION INSTRUMENTATION (debug; see swap_reject_report()) ----
1099 // Every place a proposed swap can be turned down, counted. Added to find out why an offset
1100 // surface flip is never accepted; the counters cost one relaxed atomic increment on a path
1101 // that is already refusing the operation, and nothing reads them unless a caller asks.
1102 //
1103 // The refusals TetMesh makes itself, below every hook (the valence re-test, an open ring, a
1104 // face or edge that already exists, no allowed 4-4 / 5-6 case beating the current cells, out
1105 // of slots, a duplicate tet), were once visible here only as before_pass - after_enter. They
1106 // are now reported one by one through TetMesh::op_event(); see op_accounting_report(). The
1107 // per-turn line of this block still prints that difference as `connectivity`.
1108 //
1109 // Face swaps count their own reasons (face_*, and base_before / interior_hook / base_after /
1110 // after_cells on their path) in the per-kind table alone -- swap_reject_kind_only() -- so
1111 // swap_reject_report(), which has only ever described edge swaps, keeps meaning what it meant.
1112 enum class SwapReject : int {
1113 base_before, // TetMesh::swap_*_before said no
1114 base_after, // TetMesh::swap_*_after said no
1115 valence, // wrong incident-tet count for this swap kind
1116 bbox, // edge on the bounding box
1117 surface_not_allowed, // has surface faces and allow_surface_swap() is false
1118 feature_edge, // the swap would delete a tagged feature edge (it is the operated edge)
1119 prepare_flip, // prepare_surface_flip() refused (see the flip_* reasons)
1120 interior_hook, // swap_before_interior() refused
1121 flip_open_boundary, // flipping would change the surface's boundary loops
1122 flip_not_two_surf, // not exactly two incident surface faces
1123 flip_nonmanifold_edge, // more than two incident surface faces
1124 flip_cd_nonmanifold, // a surface face already sits on the new edge (c,d)
1125 flip_new_face_surface, // (a,c,d) or (b,c,d) is already tagged surface
1126 flip_app_refused, // swap_before_surface() refused (see the app_* reasons)
1127 flip_wrong_case, // 4-4 / 5-6: the retetrahedralization is not the one that makes
1128 // the surface diagonal (c,d), so this case is not the flip
1129 app_capture_label, // application: the swap ring spans two construction labels
1130 app_capture_tag, // application: the swap ring spans two cell tags
1131 app_fid_missing, // application: a face of the pair could not be found
1132 app_class_mismatch, // application: the two faces are different tracked surfaces
1133 app_mask_mismatch, // application: the two faces carry different boundary masks
1134 app_sag_raised, // application: the flip would raise the local sag
1135 after_inverted, // a created cell is inverted
1136 after_quality, // swap_quality_allowed() said no
1137 after_cells, // swap_after_cells() refused (see the app_after_* reasons)
1138 app_after_side_conflict, // application: two ring vertices of a new cell sit on two sides
1139 app_after_no_side, // application: a new cell holds no ring vertex to take a side from
1140 after_envelope, // a new surface triangle left the envelope
1141 face_tracked_surface, // face swap: the face is a tracked surface face
1142 face_tracked_bbox, // face swap: the face is on the bounding box
1143 face_inverted, // face swap: one of the three new cells would be inverted
1144 face_not_better, // face swap: a new cell is not strictly better than the two old ones
1145 COUNT
1146 };
1154 enum class SwapStage : int {
1155 attempt,
1156 surface_attempt,
1157 before_pass,
1158 after_enter,
1159 accepted,
1160 screened,
1161 COUNT
1162 };
1163
1164 static const char* swap_reject_name(SwapReject r);
1165 static const char* swap_stage_name(SwapStage s);
1166 bool swap_reject(SwapReject r) const
1167 {
1168 m_swap_reject[size_t(r)].fetch_add(1, std::memory_order_relaxed);
1169 return swap_reject_kind_only(r);
1170 }
1173 bool swap_reject_kind_only(SwapReject r) const
1174 {
1175 m_swap_reject_by_kind[size_t(current_op_kind())][size_t(r)].fetch_add(
1176 1,
1177 std::memory_order_relaxed);
1178 return false;
1179 }
1180 void swap_stage(SwapStage s) const
1181 {
1182 m_swap_stage[size_t(s)].fetch_add(1, std::memory_order_relaxed);
1183 }
1184 void swap_counters_reset();
1186 std::string swap_reject_report() const;
1187
1188 mutable std::array<std::atomic<long>, size_t(SwapReject::COUNT)> m_swap_reject{};
1189 mutable std::array<std::atomic<long>, size_t(SwapStage::COUNT)> m_swap_stage{};
1190
1191 // ---- COLLAPSE REJECTION INSTRUMENTATION (see op_accounting_report()) ----
1192 // Every place a collapse is turned down in a hook, counted once, at the place that decided.
1193 // Before this, 85% of the collapse attempts on the deliverable cube (target_distance_rel 1e-2
1194 // / front_conv_rel 1e-4, turn 5: 213k of 232k) were refused with nothing recorded but the
1195 // ops guard's 367. What TetMesh refuses below the hooks (the link condition, a duplicate tet)
1196 // arrives through op_event(). Before-hook reasons come first, after-hook reasons from
1197 // after_base on.
1198 enum class CollapseReject : int {
1199 coarsen_length, // coarsening pass only: the edge is at or above the collapse target
1200 bbox, // v1 sits on a bounding-box face that v2 does not
1201 surface_leaves_envelope, // v1 on the surface, v2 not, and v2 not inside the envelope
1202 inverted, // a cell the collapse reshapes would invert
1203 quality, // collapse_quality_allowed() said no
1204 substructure_link, // preserve_topology, both ends on the surface: substructure link
1205 feature_leaves_tube, // a tagged feature edge the collapse moves would leave its tube
1206 feature_point, // v1 stands for a feature point and v2 is outside its ball
1207 app_both_surfaces, // application: an end on the input complex and an end on the offset
1208 app_front_unlimited, // application: an unlimited-length pass may not remove a front vertex
1209 app_leaves_input, // application: v1 on the input complex, v2 not
1210 app_leaves_offset, // application: v1 on the offset surface, v2 not
1211 app_leaves_region, // application: v1 on a region boundary, v2 not
1212 app_order2, // application: an order-2 vertex would merge into a lower-order one
1213 app_substructure_link, // application: the substructure link condition, unconditional
1214 app_ops_guard, // application: the ops divergence guard
1215 after_base, // TetMesh::collapse_edge_after said no
1216 after_connectivity, // collapse_after_connectivity() said no
1217 after_envelope, // a surface face the survivor keeps left the envelope
1218 after_face_attribute, // a face attribute found no face left to land on
1219 after_order2_chord, // an order-2 edge the survivor keeps is no longer order-2 substructure
1220 after_feature_edge, // a tagged feature edge found no edge left to land on
1221 after_coarsen_region, // coarsening only: the region's worst quality rose
1222 COUNT
1223 };
1224 static const char* collapse_reject_name(CollapseReject r);
1225 bool collapse_reject(CollapseReject r) const
1226 {
1227 m_collapse_reject[size_t(r)].fetch_add(1, std::memory_order_relaxed);
1228 return false;
1229 }
1230 mutable std::array<std::atomic<long>, size_t(CollapseReject::COUNT)> m_collapse_reject{};
1231
1232 // ---- OPERATION ACCOUNTING (counting only) ----
1233 // TetMesh reports every operation's attempt and its one outcome through op_event(); this
1234 // counts them per kind. op_accounting_report() then checks, per kind, that the outcomes add
1235 // up to the attempts, and that the before- and after-hook refusals add up to the reasons the
1236 // hooks counted (SwapReject / CollapseReject). A nonzero remainder is a refusal nobody named.
1237 void op_event(OpKind k, OpEvent e) const override
1238 {
1239 if (e == OpEvent::attempt) current_op_kind() = k;
1240 m_op_events[size_t(k)][size_t(e)].fetch_add(1, std::memory_order_relaxed);
1241 // The edge swaps whose hooks count SwapStage; see swap_reject_report().
1242 if (e == OpEvent::screened &&
1243 (k == OpKind::swap_32 || k == OpKind::swap_44 || k == OpKind::swap_56)) {
1244 swap_stage(SwapStage::screened);
1245 }
1246 }
1250 static OpKind& current_op_kind()
1251 {
1252 static thread_local OpKind k = OpKind::COUNT;
1253 return k;
1254 }
1257 std::string op_accounting_report(OpKind k) const;
1259 bool op_accounting_unexplained(OpKind k) const;
1260 void op_accounting_reset();
1261 static const char* op_kind_name(OpKind k);
1262 static const char* op_event_name(OpEvent e);
1263
1270 enum class SwapRejectRole { before_leaf, after_leaf, wrapper, per_case };
1271 static SwapRejectRole swap_reject_role(SwapReject r);
1274 {
1275 std::string before, after;
1276 long before_sum = 0, after_sum = 0;
1277 bool counted = true; // false: this kind's hooks count no reasons (split)
1278 };
1279 OpHookReasons op_hook_reasons(OpKind k) const;
1280 long op_event_count(const OpKind k, const OpEvent e) const
1281 {
1282 return m_op_events[size_t(k)][size_t(e)].load(std::memory_order_relaxed);
1283 }
1285 long op_unaccounted(OpKind k) const;
1286
1287 mutable std::array<std::array<std::atomic<long>, size_t(OpEvent::COUNT)>, size_t(OpKind::COUNT)>
1288 m_op_events{};
1289 mutable std::
1290 array<std::array<std::atomic<long>, size_t(SwapReject::COUNT)>, size_t(OpKind::COUNT) + 1>
1291 m_swap_reject_by_kind{};
1292
1305 virtual bool swap_quality_allowed(double after, double before, bool /*is_surface_flip*/) const
1306 {
1307 return after < before;
1308 }
1309
1311 {
1312 double max_energy;
1313 std::map<std::array<size_t, 3>, FaceAttributes> changed_faces;
1315 std::map<std::array<size_t, 2>, bool> changed_edges;
1316
1317 bool is_surface_flip = false;
1318 size_t sf_a = 0, sf_b = 0, sf_c = 0, sf_d = 0;
1319 FaceAttributes sf_face_attr;
1324 };
1326
1328 {
1329 size_t v1_id = 0;
1330 size_t v2_id = 0;
1331 bool is_edge_on_surface = false;
1332 bool is_edge_open_boundary = false;
1333 bool is_edge_on_feature = false;
1334 size_t edge_order = 0;
1335 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
1337 std::map<std::array<size_t, 2>, bool> changed_edges;
1338 };
1340
1342 {
1343 size_t v1_id = 0;
1344 size_t v2_id = 0;
1345 double max_energy = 0.;
1346 double edge_length = 0.;
1347 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
1351 std::vector<std::pair<std::array<size_t, 3>, FaceAttributes>> surface_faces;
1355 std::vector<std::pair<std::array<size_t, 3>, int>> renamed_orientations;
1356 std::vector<std::array<size_t, 2>> boundary_edges;
1357 std::vector<size_t> changed_tids;
1358 std::vector<double> changed_energies;
1360 std::map<std::array<size_t, 2>, bool> changed_edges;
1364 };
1366
1367 // ---- Feature-edge tag propagation (m_track_feature_edges) ----------------------------
1368 //
1369 // An edge attribute's slot is (lowest incident tet id) * 6 + local index, so it moves
1370 // whenever that tet dies. Any edge whose slot can move is an edge of an affected tet
1371 // (deleted tets are affected; created tets only affect their own six edges), so caching
1372 // every edge of every affected tet before the operation and rewriting afterwards covers
1373 // every slot that can move -- the same argument the face tags rely on.
1374 //
1375 // Restore comes in two forms because the operations differ in what they create:
1376 // * split and the swaps CREATE tets, whose slots may be reused and hold stale values;
1377 // restore_region walks every edge of every created tet and writes the cached value or
1378 // the default. The created region provably contains every surviving cached edge.
1379 // * collapse creates NO tets, and its link edges (la,lb) -- which contain neither
1380 // endpoint, a case a tet FACE cannot exhibit -- can live on in tets outside any
1381 // enumerable region. restore_remap walks the CACHE instead: remaps v1 -> v2, OR-merges
1382 // colliding pairs, and writes each surviving edge wherever its slot now is. Returns
1383 // false if a TAGGED cached edge no longer exists (the caller aborts, mirroring the
1384 // face path's try_tuple_from_face bailout).
1385
1388 const std::vector<size_t>& tids,
1389 std::map<std::array<size_t, 2>, bool>& cache);
1392 const std::vector<Tuple>& tets,
1393 const std::map<std::array<size_t, 2>, bool>& cache);
1395 const std::vector<size_t>& tids,
1396 const std::map<std::array<size_t, 2>, bool>& cache);
1399 const std::map<std::array<size_t, 2>, bool>& cache,
1400 size_t v_old,
1401 size_t v_new);
1402
1406 virtual void split_after_vertex_feature(size_t, bool) {}
1407
1408
1410 bool m_coarsen_mode = false;
1411
1412private:
1422 {
1423 std::vector<size_t> ring; // vertices to re-smooth, BFS order
1424 std::vector<size_t> frontier;
1425 std::vector<size_t> next;
1426 std::vector<size_t> one_ring;
1427 std::vector<uint32_t> stamp;
1428 uint32_t epoch = 0;
1429 VertexAttributes saved_vertex;
1430 std::vector<std::pair<size_t, double>> saved_qualities;
1431 };
1433
1435 const std::vector<size_t>&
1436 collect_vertex_ball(const size_t* seeds, size_t n_seeds, int n, CoarsenScratch& scr) const;
1437
1440 double region_max_quality_rel(const std::vector<size_t>& vids) const;
1441
1443 bool smooth_vertex_reversible(size_t vid, CoarsenScratch& scr);
1444
1451 bool is_limit_length,
1452 int lock_ring,
1453 size_t max_passes = 0,
1454 bool exact_ball_lock = false);
1455};
1456
1457} // namespace wmtk
serving as buffers for attributes data that can be modified by operations
Definition AttributeCollection.hpp:22
Several attribute collections for the same simplex type, behind one container.
Definition AttributeCollection.hpp:143
bool coord_equals(int k, const VecD &posf, const Rational &r) const
Whether coordinate k equals r, without materialising the whole position.
Definition ExactPosition.hpp:54
void store(const VecR &p)
Store an exact position that may differ from the double one.
Definition ExactPosition.hpp:60
VecR value(const VecD &posf) const
The exact position of a vertex whose double position is posf.
Definition ExactPosition.hpp:51
void clear()
The exact position is the double one: drop the stored copy.
Definition ExactPosition.hpp:70
Definition Rational.hpp:10
The rounded/exact bookkeeping shared by every mesh that keeps both coordinates.
Definition RationalPositions.h:21
Definition SurfaceTagAttributes.h:24
a Tuple refers to a global vid and a global tet id, and a local edge id and local face id
Definition TetMesh.h:60
Definition TetMesh.h:32
size_t vert_capacity() const
get the current largest global vid
Definition TetMesh.h:379
Tuple tuple_from_vertex(size_t vid) const
get a Tuple from global vertex index
Definition TetMesh.cpp:702
virtual std::array< size_t, 3 > orient_tracked_face(const std::array< size_t, 3 > &f, const std::vector< size_t > &tets) const
Definition TetMesh.h:687
What tetwild and simwild's 3D mesh share.
Definition TetOptimizerMesh.h:51
bool m_collapse_limit_length
Definition TetOptimizerMesh.h:451
void smooth_vertices_colored(const std::vector< std::pair< std::string, Tuple > > &ops)
One smoothing sweep over ops (all "vertex_smooth"), one color class at a time.
Definition TetOptimizerMesh.cpp:435
std::string op_accounting_report(OpKind k) const
Definition TetOptimizerMesh.cpp:1456
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:494
bool m_tracks_orientation
The application set FaceAttributes::m_orientation at insertion, so the tracked surface carries the in...
Definition TetOptimizerMesh.h:119
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:308
virtual void collapse_after_features(size_t, size_t)
Definition TetOptimizerMesh.h:1071
optimization::NewtonCounters m_newton
Definition TetOptimizerMesh.h:447
std::shared_ptr< history::VolumeRecorder > m_recorded_volume
Definition TetOptimizerMesh.h:610
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:694
size_t m_force_split_count
Force-splits taken in the current split pass. Diagnostic only.
Definition TetOptimizerMesh.h:458
AttributeContainerGroup m_vertex_attr_group
What p_vertex_attrs points at, so a derived class can register more.
Definition TetOptimizerMesh.h:158
bool vertex_is_on_surface(const size_t vid) const override
Is a vertex part of the substructure.
Definition TetOptimizerMesh.cpp:1094
SwapStage
Definition TetOptimizerMesh.h:1154
bool collapse_edge_after(const Tuple &t) override
User specified modifications and desideratas for after an edge collapse.
Definition TetOptimizerMeshCollapse.cpp:402
SwapRejectRole
Definition TetOptimizerMesh.h:1270
std::unique_ptr< std::atomic< int >[]> m_high_valence_claim
Per-pass claims for the shared high-valence split gate.
Definition TetOptimizerMesh.h:466
virtual std::shared_ptr< Envelope > smoothing_energy_envelope(const size_t vid) const =0
Envelope a surface vertex is pulled toward while smoothing. A real envelope, never a composite (see s...
std::vector< size_t > all_vertex_ids() const override
Every live vertex, in the mesh's own iteration order.
Definition TetOptimizerMesh.cpp:483
double region_max_quality_rel(const std::vector< size_t > &vids) const
Definition TetOptimizerMeshCollapse.cpp:663
bool m_coarsen_mode
Set for the duration of coarsen_mesh(); read-only while a pass is running.
Definition TetOptimizerMesh.h:1410
bool checks_tracked_surface() const override
m_params.check_surface_folds; see there.
Definition TetOptimizerMesh.h:626
virtual std::shared_ptr< Envelope > smoothing_containment_envelope(const size_t, const std::array< size_t, 3 > &face, const FaceAttributes &attr) const
Envelope the smoother checks tracked face face (attributes attr) at the moved vertex vid against; nul...
Definition TetOptimizerMesh.h:883
virtual void split_after_vertex_feature(size_t, bool)
Definition TetOptimizerMesh.h:1406
bool swap_face_after(const Tuple &t) override
User specified modifications and desideratas for after a 2-3 face swap.
Definition TetOptimizerMeshSwaps.cpp:587
EdgeAttCol m_feature_edge_attribute
Sized, protected and rolled back only once enable_feature_edge_tracking() ran.
Definition TetOptimizerMesh.h:261
bool m_in_operation_pass
True while a pass of the shared operations runs.
Definition TetOptimizerMesh.h:207
void record_surface_history(const std::string &metadata)
Definition TetOptimizerMesh.cpp:879
virtual std::shared_ptr< Envelope > surface_envelope_for_face(const std::array< size_t, 3 > &vids, const FaceAttributes &attr) const
Envelope the tracked-surface triangle vids must stay inside, given the attributes attr it carries – o...
Definition TetOptimizerMesh.h:729
virtual void update_attributes()
Update the attributes of the mesh after an iteration of operations.
Definition TetOptimizerMesh.h:570
virtual void smoothing_pass_done()
Definition TetOptimizerMesh.h:989
bool swap_edge_44_after(const Tuple &t) override
User specified modifications and desideratas for after a 4-4 edge swap.
Definition TetOptimizerMeshSwaps.cpp:746
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:116
std::vector< std::array< size_t, 3 > > oriented_tracked_faces() const
The tracked surface as an oriented soup: each tracked face emitted |m_orientation| times,...
Definition TetOptimizerMesh.cpp:704
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:521
virtual void split_after_vertex(size_t, bool)
Application metadata not represented by the shared vertex attributes.
Definition TetOptimizerMesh.h:1084
bool vertex_has_feature_edge(size_t vid) const
Definition TetOptimizerMesh.cpp:1122
virtual bool boundary_edges_at_vertex_inside(size_t) const
Definition TetOptimizerMesh.h:901
std::array< size_t, 3 > orient_tracked_face(const std::array< size_t, 3 > &f, const std::vector< size_t > &tets) const override
Definition TetOptimizerMesh.cpp:1000
void feature_edges_cache(const std::vector< size_t > &tids, std::map< std::array< size_t, 2 >, bool > &cache)
Cache the feature tag of every edge of every tet in tids.
Definition TetOptimizerMesh.cpp:1255
bool swap_edge_56_after(const Tuple &t) override
User specified modifications and desideratas for after a 5-6 edge swap.
Definition TetOptimizerMeshSwaps.cpp:896
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:1076
bool collapse_breaks_feature_point(const size_t v1_id, const size_t v2_id) const
Definition TetOptimizerMesh.cpp:1198
bool storage_grows_on_demand() const override
Definition TetOptimizerMesh.h:473
virtual double cell_quality(const size_t tid) const =0
The quality of cell tid, and how to write it.
std::shared_ptr< Envelope > m_feature_envelope
Envelope around the input feature curves: the tube a tagged edge must stay in.
Definition TetOptimizerMesh.h:280
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:916
std::vector< std::vector< uint64_t > > m_recorded_sources
The input triangles each face of the recorded surface's first state lies on.
Definition TetOptimizerMesh.h:654
virtual bool collapse_before_vertex(size_t, size_t, double)
Definition TetOptimizerMesh.h:1057
void record_volume_history()
Definition TetOptimizerMesh.cpp:913
virtual bool smoothing_position_is_allowed(const size_t vid, const Vector3d &p) const
Definition TetOptimizerMesh.h:408
virtual std::vector< size_t > active_vertices() const
Definition TetOptimizerMesh.cpp:559
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:440
size_t get_order_of_vertex(const size_t vid) const override
Get the order of a vertex.
Definition TetOptimizerMesh.cpp:1104
std::string m_debug_pass_name
Definition TetOptimizerMesh.h:661
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:323
AttributeContainerGroup m_edge_attr_group
What p_edge_attrs points at, once a collection is registered with it.
Definition TetOptimizerMesh.h:196
std::string swap_reject_report() const
One line per nonzero counter, for a per-turn log. Does not reset.
Definition TetOptimizerMeshSwaps.cpp:225
std::vector< Vector3d > m_feature_points
Definition TetOptimizerMesh.h:354
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:1050
void feature_edges_restore_region(const std::vector< Tuple > &tets, const std::map< std::array< size_t, 2 >, bool > &cache)
Write back tags over every edge of every tet in tets (created regions).
Definition TetOptimizerMesh.cpp:1289
virtual double smoothing_ring_energy(const std::vector< Tuple > &ring, const bool stored) const
The number the shared smoother's projected step compares for a whole one-ring: a vertex held on a sur...
Definition TetOptimizerMesh.h:951
bool collapse_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge collapse before changing the connectivity.
Definition TetOptimizerMeshCollapse.cpp:100
virtual bool is_open_boundary_edge(const Tuple &e)
Whether edge e lies on the boundary of the tracked surface.
Definition TetOptimizerMesh.h:700
std::optional< history::SurfaceHistory > finish_surface_history(const history::SurfaceHistory *input=nullptr)
Bring the recorded surface up to date with the tracked faces, stop recording, log what the history ho...
Definition TetOptimizerMesh.cpp:937
int m_iterations_used
Shared TetWild/SimWild outer optimization schedule.
Definition TetOptimizerMesh.h:633
std::vector< std::pair< PositionKey, std::vector< uint32_t > > > m_insertion_sources
Definition TetOptimizerMesh.h:606
virtual void log_smoothing_pass_accounting()
Definition TetOptimizerMesh.h:984
bool is_tracked_face(size_t tid, int j) const override
The faces with m_is_surface_fs, for a surface history (TetMesh::start_surface_history).
Definition TetOptimizerMesh.cpp:995
bool is_inverted_f(const Tuple &loc) const
Inversion check using only the double positions.
Definition TetOptimizerMesh.cpp:571
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:1096
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:538
virtual bool optimization_bare_coarsen_passes() const
Whether the loop opens with an UNLIMITED-LENGTH collapse pass.
Definition TetOptimizerMesh.h:1022
AttributeContainerGroup m_face_attr_group
What p_face_attrs points at, so a derived class can register more.
Definition TetOptimizerMesh.h:173
std::vector< std::array< size_t, 2 > > tracked_feature_edges() const override
The tagged feature edges (m_feature_edge_attribute) that are edges of tracked faces.
Definition TetOptimizerMesh.cpp:754
virtual bool split_adjust_position(size_t, const std::vector< Tuple > &)
Definition TetOptimizerMesh.h:1082
std::atomic< size_t > m_inconsistent_orientation_flips
Surface flips that joined two faces not oriented alike (a fold of the tracked surface,...
Definition TetOptimizerMesh.h:130
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:1041
bool split_edge_is_due(const Tuple &e) const
Definition TetOptimizerMeshSplit.cpp:125
bool round_vertex(const size_t vid) override
Definition TetOptimizerMesh.h:684
bool surface_triangle_is_outside(const size_t a, const size_t b, const size_t c, const FaceAttributes &attr) const
Definition TetOptimizerMesh.h:739
uint32_t m_op_epoch
Definition TetOptimizerMesh.h:1033
bool m_track_feature_edges
Whether the shared operations maintain m_feature_edge_attribute.
Definition TetOptimizerMesh.h:270
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:845
std::pair< size_t, size_t > feature_retention(double *worst_ratio=nullptr) const
Definition TetOptimizerMesh.cpp:1219
static constexpr double MAX_ENERGY
The sentinel get_quality returns for an element AMIPS cannot score.
Definition TetOptimizerMesh.h:421
bool split_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge split before changing the connectivity.
Definition TetOptimizerMeshSplit.cpp:141
bool use_colored_smoothing() const
Whether this pass smooths by color class (see OptimizerParameters::colored_smoothing).
Definition TetOptimizerMesh.cpp:430
virtual void optimization_iteration_done(int)
Definition TetOptimizerMesh.h:1025
std::vector< std::pair< std::array< size_t, 2 >, int > > tracked_surface_boundary() const
Mesh edges where the oriented tracked surface has a boundary.
Definition TetOptimizerMesh.cpp:719
bool swap_edge_after(const Tuple &t) override
User specified modifications and desideratas for after a 3-2 edge swap.
Definition TetOptimizerMeshSwaps.cpp:409
void update_attributes_and_history()
update_attributes(), then the change it made to the tracked surface, if recording one.
Definition TetOptimizerMesh.cpp:985
Eigen::Vector3d tracked_area_normal(const std::vector< std::array< size_t, 3 > > &faces) const
Definition TetOptimizerMesh.cpp:782
std::set< simplex::Edge > m_force_split_edges
Definition TetOptimizerMesh.h:456
bool swap_reject_kind_only(SwapReject r) const
Definition TetOptimizerMesh.h:1173
void enable_feature_edge_tracking()
Turn on feature-edge tracking. The collection joins m_edge_attr_group beside whatever the application...
Definition TetOptimizerMesh.h:294
bool feature_point_ball_contains(const size_t vid, const Vector3d &p) const
Definition TetOptimizerMesh.cpp:1209
bool smooth_before(const Tuple &t) override
The smoothing hooks. A derived class overriding them – or invariants(), which a smooth also runs – mu...
Definition TetOptimizerMesh.cpp:338
void add_edge_attributes(AbstractAttributeContainer *c)
Register an edge collection with m_edge_attr_group and point p_edge_attrs at the group.
Definition TetOptimizerMesh.h:235
optimization::SmoothRejectCounters m_smooth_rejects
Why smoothing attempts were refused, reported once per pass.
Definition TetOptimizerMesh.h:443
static OpKind & current_op_kind()
Definition TetOptimizerMesh.h:1250
size_t m_split_order_waits
The current split pass's ExecutePass::waits() and wait_defects().
Definition TetOptimizerMesh.h:497
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:715
bool round(const Tuple &v)
Round a vertex position to floating point, if that inverts no incident tet.
Definition TetOptimizerMesh.cpp:639
double m_feature_eps
Definition TetOptimizerMesh.h:357
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:1447
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:674
std::array< std::array< double, 3 >, 3 > PositionKey
A tracked face by its corners' positions, sorted.
Definition TetOptimizerMesh.h:601
virtual std::tuple< double, double > optimization_quality_stats()
Definition TetOptimizerMesh.cpp:31
virtual double smoothing_cell_energy(const size_t, const double quality) const
The number the shared smoother compares for one cell, given the cell's quality (AMIPS^3) at the posit...
Definition TetOptimizerMesh.h:932
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:703
bool m_track_feature_points
Whether the shared operations maintain the ids (enable_feature_point_tracking()).
Definition TetOptimizerMesh.h:359
bool feature_edges_at_vertex_inside(size_t vid) const
Definition TetOptimizerMesh.cpp:1179
double m_s_amips
Definition TetOptimizerMesh.h:432
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:771
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:1074
long op_unaccounted(OpKind k) const
Attempts minus every outcome: 0 unless an exit of the TetMesh operation reports nothing.
Definition TetOptimizerMesh.cpp:1402
void substructure_feature_neighbors(size_t vid, std::vector< size_t > &out) const override
One-ring vertices x of vid where (vid, x) is 1D substructure NOT derivable from the surface complex (...
Definition TetOptimizerMesh.cpp:1165
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:602
virtual bool swap_quality_allowed(double after, double before, bool) const
Definition TetOptimizerMesh.h:1305
bool feature_edges_restore_remap(const std::map< std::array< size_t, 2 >, bool > &cache, size_t v_old, size_t v_new)
Write back tags for every cached edge, with v_old renamed to v_new (collapse).
Definition TetOptimizerMesh.cpp:1312
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:1090
static constexpr size_t NO_FEATURE_POINT
A vertex that stands for no feature point. See FeaturePointAttributes.
Definition TetOptimizerMesh.h:342
OptimizerParameters & m_params
Definition TetOptimizerMesh.h:425
FeaturePointAttCol m_feature_point_attribute
Registered with m_vertex_attr_group only once enable_feature_point_tracking() ran.
Definition TetOptimizerMesh.h:350
std::optional< std::vector< uint8_t > > finish_volume_history(const std::map< int64_t, std::string > &tag_names={})
Definition TetOptimizerMesh.cpp:919
bool m_preserve_feature_points
Whether the collapse and smoothing policy is on (its preserve argument).
Definition TetOptimizerMesh.h:361
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:389
void throw_if_in_operation_pass(const char *call) const
Definition TetOptimizerMesh.h:214
void on_slot_storage_grown() override
Definition TetOptimizerMesh.h:479
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:242
std::shared_ptr< Envelope > m_envelope
Surface envelope: what a surface vertex is pulled toward and checked against.
Definition TetOptimizerMesh.h:428
void enable_feature_point_tracking(const bool preserve)
Turn on feature-point tracking, and the policy when preserve.
Definition TetOptimizerMesh.h:376
size_t substructure_order_of_edge(const std::array< size_t, 2 > &vids) const override
The orders substructure_link_condition consults, overridable so an application can widen the 1D subst...
Definition TetOptimizerMesh.cpp:1133
bool vertex_is_rounded(const size_t vid) const override
Whether this vertex's double position is currently trusted.
Definition TetOptimizerMesh.h:677
std::atomic< size_t > m_surface_fold_refusals
The operations check_surface_folds refused.
Definition TetOptimizerMesh.h:630
bool face_is_on_surface(const size_t fid) const override
Is a face part of the substructure.
Definition TetOptimizerMesh.cpp:1099
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:379
bool smooth_after(const Tuple &t) override
User specified modifications and desideratas for after smoothing a vertex.
Definition TetOptimizerMesh.cpp:352
Definition Simplex.hpp:46
Definition enumerable_thread_specific.hpp:37
The parameters tetwild, triwild and simwild all share.
Definition OptimizerParameters.h:29
bool check_surface_folds
Definition OptimizerParameters.h:212
Per-thread buffers for the coarsening composite, so it allocates nothing.
Definition TetOptimizerMesh.h:1422
What coarsen_mesh() achieved, for the run report. Zeroed when the pass is off.
Definition TetOptimizerMesh.h:814
Definition TetOptimizerMesh.h:1342
std::vector< std::pair< std::array< size_t, 3 >, FaceAttributes > > surface_faces
Definition TetOptimizerMesh.h:1351
std::map< std::array< size_t, 2 >, bool > changed_edges
Feature-edge tags of the affected tets, by sorted vid pair (m_track_feature_edges).
Definition TetOptimizerMesh.h:1360
std::vector< std::pair< std::array< size_t, 3 >, int > > renamed_orientations
Definition TetOptimizerMesh.h:1355
double region_max_rel_before
Definition TetOptimizerMesh.h:1363
Per-edge feature tag: does this tet edge tile an input feature curve.
Definition TetOptimizerMesh.h:256
Definition TetOptimizerMesh.h:344
size_t m_feature_point_id
Index into m_feature_points, or NO_FEATURE_POINT.
Definition TetOptimizerMesh.h:346
A kind's hook refusals by reason: the nonzero leaves as "name=n" and their sums.
Definition TetOptimizerMesh.h:1274
Definition TetOptimizerMesh.h:1328
std::map< std::array< size_t, 2 >, bool > changed_edges
Feature-edge tags of the affected tets, by sorted vid pair (m_track_feature_edges).
Definition TetOptimizerMesh.h:1337
Definition TetOptimizerMesh.h:639
Definition TetOptimizerMesh.h:1311
int sf_orientation
Orientation of the flipped pair, measured along [a,b,c] (and so along [b,a,d]).
Definition TetOptimizerMesh.h:1321
std::map< std::array< size_t, 2 >, bool > changed_edges
Feature-edge tags of the affected tets, by sorted vid pair (m_track_feature_edges).
Definition TetOptimizerMesh.h:1315
bool sf_orientation_mismatch
The pair's two faces were not oriented alike; see prepare_surface_flip.
Definition TetOptimizerMesh.h:1323
Definition TetOptimizerMesh.h:54
size_t partition_id
Required for multi-threading.
Definition TetOptimizerMesh.h:77
size_t m_order
Definition TetOptimizerMesh.h:71
bool m_is_rounded
Definition TetOptimizerMesh.h:61
A complex and the edits it went through, in commit order.
Definition History.hpp:101
How the vertex solves of a smoothing pass ended: Newton iterations taken and the status polysolve sto...
Definition SmoothVertex.hpp:76
Why a smoothing attempt was refused, counted per pass.
Definition SmoothVertex.hpp:32
A topological fingerprint of a tracked surface inside a tet mesh.
Definition SurfaceTopology.hpp:23