Wildmeshing Toolkit
Loading...
Searching...
No Matches
TopoOffsetTetMesh.h
1#pragma once
2
3#include <array>
4#include <atomic>
5#include <cmath>
6#include <cstdint>
7#include <cstdlib>
8#include <functional>
9#include <map>
10#include <mutex>
11#include <optional>
12#include <set>
13#include <string>
14
15#include <wmtk/TetMesh.h>
16#include <wmtk/TetOptimizerMesh.h>
17#include <wmtk/envelope/Envelope.hpp>
18#include <wmtk/optimization/EnergySum.hpp>
19#include <wmtk/optimization/solver.hpp>
20#include <wmtk/simplex/Simplex.hpp>
21#include <wmtk/threading/enumerable_thread_specific.hpp>
22#include "OffsetPotential.hpp"
23#include "Parameters.h"
24#include "SimplicialComplexBVH.hpp"
25#include "TagEnvelopes.hpp"
26
27// clang-format off
28#include <wmtk/utils/DisableWarnings.hpp>
29#include <wmtk/utils/EnableWarnings.hpp>
30// clang-format on
31
32using CellTag = std::set<int64_t>;
33
34
35namespace wmtk::components::topological_offset {
36
37const int64_t TEMP_OFFSET_TET_TAG = -1;
38const CellTag TEMP_OFFSET_TET_TAG_SET{TEMP_OFFSET_TET_TAG};
39
40
41// for all attributes:
42// label: 0=default, 1=input, 2=offset
43
54{
55public:
56 int label = 0;
57 size_t component_id = 0;
58 bool m_is_on_input = false; // on the input complex
59 bool m_is_on_offset = false; // on the offset surface itself
60 bool m_is_on_region = false; // on some OTHER tag region's boundary
63 Vector3d m_turn_start = Vector3d::Zero();
64 bool m_turn_start_valid = false;
65
74 uint64_t m_boundary_mask = 0;
75
80 uint32_t m_born_epoch = 0;
81};
82
83
85{
86public:
87 int label = 0; // label: 0=default, 1=input, 2=offset
88};
89
90
94{
95public:
96 int label = 0; // label: 0=default, 1=input, 2=offset
101 bool on_sheet = false;
102};
103
104
106{
107public:
108 int label = 0; // label: 0=default, 1=input, 2=offset
109 CellTag tag;
110 double m_quality = 0; // AMIPS energy, kept up to date by smoothing
117 bool rest_valid = false;
118 std::array<Vector3d, 4> rest_pos;
119};
120
121
136{
137public: // mode for splitting in marching tets
138 enum class EdgeSplitMode {
139 Midpoint = 0, // construction: simplicial embedding AND marching_tets
140 SphereTrace = 1, // marching_tets under sphere_trace_initialization: sphere tracing
141 // along the edge to d(x) = target_distance, midpoint when the trace
142 // leaves the edge
143 Optimization = 5 // the optimization phase; the shared engine places the vertex
144 };
145
146public:
147 std::array<size_t, 4> m_init_counts = {{0, 0, 0, 0}};
148 size_t m_tags_count;
153 int64_t m_sheet_tag = -1;
155 MatrixXd m_sheet_V;
156 MatrixXi m_sheet_F;
179 std::shared_ptr<SimplicialComplexBVH> m_input_complex_bvh;
180
189 std::shared_ptr<OffsetPotential3D> m_offset_potential;
190
200 std::shared_ptr<SampleEnvelope> m_input_complex_envelope;
201
212 int m_n_regions = 0;
213 std::vector<std::shared_ptr<OffsetPotential3D>> m_region_potentials;
217 std::vector<std::shared_ptr<SimplicialComplexBVH>> m_region_bvhs;
218 std::vector<int64_t> m_phi_vert_region;
219 std::vector<int64_t> m_phi_seg_region;
220 std::vector<int64_t> m_phi_face_region;
221 std::vector<int64_t> m_phi_point_region;
222 std::vector<int> m_cell_region;
223 std::vector<int> m_vertex_region;
224 void init_region_potentials(double delta, double effective_factor);
227 void assign_band_regions(bool log = true);
229 void log_front_profile(size_t vid);
230 int vertex_region(const size_t vid) const
231 {
232 return vid < m_vertex_region.size() ? m_vertex_region[vid] : -1;
233 }
234 int edge_region(const size_t va, const size_t vb) const
235 {
236 const int a = vertex_region(va), b = vertex_region(vb);
237 return (a >= 0 && a == b) ? a : -1;
238 }
239 const OffsetPotential3D& potential_for_region(const int region) const
240 {
241 return (region >= 0 && size_t(region) < m_region_potentials.size())
242 ? *m_region_potentials[size_t(region)]
244 }
245 const OffsetPotential3D& potential_for(const size_t vid) const
246 {
247 return potential_for_region(vertex_region(vid));
248 }
251 std::shared_ptr<const OffsetPotential3D> potential_ptr_for(const size_t vid) const
252 {
253 const int r = vertex_region(vid);
254 return (r >= 0 && size_t(r) < m_region_potentials.size()) ? m_region_potentials[size_t(r)]
256 }
257 const OffsetPotential3D& potential_for_edge(const size_t va, const size_t vb) const
258 {
259 return potential_for_region(edge_region(va, vb));
260 }
262 const OffsetPotential3D& potential_for_face(const Tuple& f) const;
263
276 std::map<int64_t, std::shared_ptr<SampleEnvelope>> m_tag_envelopes;
277
280 std::map<int64_t, int> m_tag_bit;
281
284 mutable std::map<uint64_t, std::shared_ptr<SampleEnvelope>> m_isect_cache;
285 mutable std::mutex m_isect_mutex;
286
294 mutable std::map<uint64_t, std::shared_ptr<SampleEnvelope>> m_offset_isect_cache;
295
305 std::shared_ptr<SampleEnvelope> containment_for(uint64_t region_mask, bool on_offset) const;
306
312 bool project_into_containment(size_t vid, Vector3d& x) const;
313
325 enum class OptPhase { A, B, Single };
326
329 bool phase_places_front() const { return m_phase != OptPhase::A; }
330
332 OptPhase m_phase = OptPhase::A;
333
335 bool m_freeze_front = false;
336
355 enum class EnvelopeSetup { PerTag, WallComplex };
356 EnvelopeSetup envelope_setup() const
357 {
358 return m_offset_params.deform_others ? EnvelopeSetup::WallComplex : EnvelopeSetup::PerTag;
359 }
360 static constexpr int64_t m_wall_tag = -2;
361 static constexpr int64_t m_complex_tag = -3;
363 std::string envelope_key_name(int64_t tag) const;
366 bool face_is_complex_boundary(const Tuple& f) const;
372 void build_boundary_envelopes(const char* when, EnvelopeSetup setup);
373
381 std::shared_ptr<SampleEnvelope> m_offset_envelope;
382
386
389 void check_no_vertex_on_both_surfaces(const char* when) const;
390
393
400
401 EdgeSplitMode m_edge_split_mode = EdgeSplitMode::Midpoint;
402
403 // tag name maps
404 std::map<std::string, int64_t> m_tag_name_to_id;
405 std::map<int64_t, std::string> m_tag_id_to_name;
406 CellTag m_offset_output_tag_ids;
407
408 // if in 'singlebody' mode
409 bool m_singlebody = false;
410 int64_t m_single_tag;
411
412 // just for retaining in output. dont actually use
413 bool m_has_envelope = false;
414 MatrixXd m_V_envelope;
415 MatrixXi m_F_envelope;
416 // m_envelope itself lives on the base, which is what checks tracked-surface triangles
417 // against it.
418 double m_envelope_eps = -1;
419
429 static constexpr int INPUT_SURFACE_CLASS = 0;
430 static constexpr int OFFSET_SURFACE_CLASS = 1;
431
434
439 // m_vertex_attribute and m_face_attribute are the base's; these are registered alongside
440 // them in its attribute groups.
441 VertexExtraCol m_vertex_extra;
442 FaceExtraCol m_face_extra;
443 EdgeAttCol m_edge_attribute;
444 TetAttCol m_tet_attribute;
445
446 TopoOffsetTetMesh(Parameters& _m_offset_params, int _num_threads = 0)
447 : wmtk::TetOptimizerMesh(_m_offset_params, nullptr)
448 , m_offset_params(_m_offset_params)
449 {
450 NUM_THREADS = _num_threads;
451 // The base owns the vertex and face slots; register the offset's own data with its
452 // groups so it is resized, protected and rolled back with them.
453 m_vertex_attr_group.add(&m_vertex_extra);
454 m_face_attr_group.add(&m_face_extra);
455 p_edge_attrs = &m_edge_attribute;
456 p_tet_attrs = &m_tet_attribute;
457
458 m_collapse_check_link_condition = false;
459 m_collapse_check_manifold = false;
460
461 // As in 2D. The per-vertex Newton solver logs a line per smoothing attempt at info level,
462 // which is one line per vertex per pass and buries the run's own output.
463 optimization::deactivate_opt_logger();
464 }
465
466 ~TopoOffsetTetMesh() override = default;
467
469
470 double cell_quality(const size_t tid) const override { return m_tet_attribute[tid].m_quality; }
471 void set_cell_quality(const size_t tid, const double q) override
472 {
473 m_tet_attribute[tid].m_quality = q;
474 }
475
483 void set_vertex_position(const size_t vid, const Vector3d& p)
484 {
485 m_vertex_attribute[vid].m_posf = p;
486 m_vertex_attribute[vid].m_pos = to_rational(p);
487 m_vertex_attribute[vid].m_is_rounded = true;
488 }
489
493 bool face_is_offset(const size_t fid) const
494 {
495 return m_face_attribute[fid].m_is_surface_fs &&
496 m_face_attribute[fid].m_surface_class == OFFSET_SURFACE_CLASS;
497 }
498 bool face_is_region(const size_t fid) const
499 {
500 return m_face_attribute[fid].m_is_surface_fs &&
501 m_face_attribute[fid].m_surface_class != OFFSET_SURFACE_CLASS;
502 }
503
511 {
512 FaceAttributes tags;
513 FaceExtra extra;
514 };
515 FaceSnapshot face_snapshot(const size_t fid) const
516 {
517 return FaceSnapshot{m_face_attribute[fid], m_face_extra[fid]};
518 }
519 void restore_face(const size_t fid, const FaceSnapshot& s)
520 {
521 m_face_attribute[fid] = s.tags;
522 m_face_extra[fid] = s.extra;
523 }
524
533
537 bool cell_in_region(const size_t tid) const
538 {
539 const int l = m_tet_attribute[tid].label;
540 return l == 1 || l == 2;
541 }
543 bool cell_is_input_complex(const size_t tid) const { return m_tet_attribute[tid].label == 1; }
545 bool cell_is_offset_band(const size_t tid) const { return m_tet_attribute[tid].label == 2; }
546
548 void optimize_offset(const std::filesystem::path& output_file);
549
556 std::pair<double, double> compute_distance_deviation() const;
557
560 mutable size_t m_worst_dist_vid = static_cast<size_t>(-1);
561 void log_worst_dist_vertex() const;
562
571 bool face_is_offset_surface_live(const Tuple& f) const;
573 bool edge_is_offset_surface_live(size_t a, size_t b) const;
576 std::vector<std::array<size_t, 2>> offset_surface_edges() const;
578 std::vector<std::array<size_t, 3>> offset_surface_faces() const;
580 std::vector<Tuple> offset_surface_faces_live_at(size_t vid) const;
584 bool vertex_has_live_offset_face(size_t vid) const;
601 void refresh_offset_membership(size_t vid);
604 std::pair<size_t, size_t> offset_membership_mismatches() const;
607 void check_offset_membership(const char* when) const;
608
630 mutable std::atomic<long long> m_offset_face_lookup_misses{0};
634 mutable std::atomic<long long> m_offset_face_invalid_tuple{0};
637 void report_offset_face_lookup_misses(const char* when) const;
638
659 std::vector<char> offset_surface_foldover_labels() const;
660
663 std::vector<std::array<double, 8>> optimization_metrics;
666 std::vector<std::array<int, 3>> churn_counts;
668 std::vector<std::array<int, 3>> op_counts;
671 int m_ab_round = 0;
673 mutable size_t m_debug_seq = 0;
677 mutable std::vector<std::string> m_debug_frame_labels;
678 mutable std::map<std::string, std::vector<size_t>> m_debug_pvd_series;
683 void write_debug_pvd() const;
686 mutable int m_debug_pass = 0;
687 mutable int m_debug_last_round = -1;
688 mutable char m_debug_last_phase = '?';
694 bool m_converged = false;
699 double m_quality_max_amips = 0.;
700
703 std::atomic<int> iter_cnt_split_born{0};
704 std::atomic<int> iter_cnt_recollapsed{0};
705 std::atomic<int> iter_cnt_recollapsed_same_pass{0};
706 std::atomic<int> iter_cnt_split = 0, iter_cnt_collapse = 0, iter_cnt_swap = 0;
707 std::atomic<int> iter_cnt_collapse_offset_removed{0};
710 std::atomic<int> iter_cnt_swap_offset_reject{0};
714 std::atomic<int> iter_cnt_swap_guard_reject{0};
715
725 static constexpr long long kFlipTraceEvery = 20000;
726 std::atomic<long long> flip_trace_n{0};
727 std::atomic<long long> flip_trace_nonmono{
728 0};
729 std::atomic<long long> flip_trace_bar{0};
732 std::array<std::atomic<long long>, 8> flip_trace_dec{};
733 void flip_trace_record(double before, double after);
734
753 mutable std::atomic<long long> funnel_offered{0};
755 mutable std::array<std::atomic<long long>, 3> funnel_kind{};
758 mutable std::atomic<long long> funnel_cases{0};
764 mutable std::atomic<long long> funnel_case_inverted{0};
765 mutable std::atomic<long long> funnel_case_not_better{0};
766 mutable std::atomic<long long> funnel_case_better{0};
767 mutable std::atomic<long long> funnel_quality{0};
768 mutable std::atomic<long long> funnel_quality_ok{0};
769 mutable std::atomic<long long> funnel_committed{0};
770 std::string flip_funnel_report() const;
771 void flip_funnel_reset();
773 std::atomic<int> iter_cnt_split_offset_before{0};
774 std::atomic<int> iter_cnt_split_offset{0};
778 std::atomic<long> m_split_order_waits{0};
779 mutable std::atomic<long> m_split_off_longest{0};
782 static bool& split_off_longest()
783 {
784 static thread_local bool off = false;
785 return off;
786 }
787 void op_event(OpKind k, OpEvent e) const override;
790 bool split_edge_is_due(const Tuple& e) const;
791
795 {
796 bool is_edge_on_region = false;
797 bool is_edge_on_offset = false;
798 std::map<simplex::Edge, TetAttributes> tets;
801 double parent_q_max = -1.;
804 double parent_flatness = 1.;
805 };
807
808 bool marching_split_edge_before(const Tuple& t);
809 bool marching_split_edge_after(const Tuple& t);
825 const Vector3d& p_in,
826 const Vector3d& p_out,
827 Vector3d& p_new,
828 size_t& steps) const;
832 size_t m_marching_root_splits = 0, m_marching_midpoint_splits = 0;
833 size_t m_marching_trace_steps = 0, m_marching_trace_steps_max = 0;
834
843 bool collapse_edge_before(const Tuple& t) override;
845 bool collapse_edge_after(const Tuple& t) override;
846 bool collapse_before_vertex(size_t v1, size_t v2, double edge_length) override;
847 bool collapse_after_connectivity(
848 size_t v1,
849 size_t v2,
850 const std::vector<std::array<size_t, 2>>& boundary_edges) override;
851 bool collapse_is_order_2_edge(const std::array<size_t, 2>& e) override
852 {
853 return is_order_2_edge(e);
854 }
855 void collapse_after_vertex(size_t v1, size_t v2) override;
856
862 bool swap_before_interior(const std::vector<size_t>& tids) override;
863 bool swap_before_surface(
864 const std::vector<size_t>& tids,
865 size_t a,
866 size_t b,
867 size_t c,
868 size_t d) override;
869 bool swap_after_cells(const std::vector<size_t>& tids, bool is_surface_flip) override;
870
875 bool split_before_cells(const Tuple& edge, const std::vector<Tuple>& parents) override;
876 bool split_after_cells(size_t v1, size_t v2, size_t v_new, const std::vector<Tuple>& children)
877 override;
878 bool split_adjust_position(size_t v_new, const std::vector<Tuple>& children) override;
879 void split_after_vertex(size_t v_new, bool is_edge_open_boundary) override;
880
883 bool is_open_boundary_edge(const Tuple& e) override { return is_order_2_edge(e); }
884
885 bool smooth_before(const Tuple& t) override;
886 bool smooth_after(const Tuple& t) override;
887
896 bool vertex_is_on_domain_boundary(const size_t vid) const
897 {
898 return !m_vertex_attribute[vid].on_bbox_faces.empty();
899 }
900 bool face_is_on_domain_boundary(const size_t fid) const
901 {
902 return m_face_attribute[fid].m_is_bbox_fs >= 0;
903 }
904
915
918 bool is_edge_on_region(const Tuple& loc);
919 bool is_edge_on_offset(const Tuple& loc);
920
924
933
938 {
939 std::atomic<int> attempted{0};
940 std::atomic<int> before_bbox{0};
941 std::atomic<int> before_unrounded{0};
943 0};
946 std::atomic<int> offset_attempted{0};
947 std::atomic<int> offset_accepted{0};
948 std::atomic<int> interior_attempted{0};
949 std::atomic<int> region_attempted{0};
952 std::atomic<long long> res_before_nano{0};
953 std::atomic<long long> res_after_nano{0};
954 std::atomic<long long> res_max_before_nano{0};
955 std::atomic<long long> res_max_after_nano{0};
956
957 void reset()
958 {
959 for (std::atomic<int>* c :
960 {&attempted,
970 c->store(0);
971 }
972 for (std::atomic<long long>* c :
973 {&res_before_nano, &res_after_nano, &res_max_before_nano, &res_max_after_nano}) {
974 c->store(0);
975 }
976 }
977 };
978 SmoothTrace m_smooth_trace;
979
986 optimization::NewtonCounters m_newton_plastic;
987 void log_smoothing_pass_accounting() override;
988
994 mutable std::atomic<size_t> m_needle_smooth_offered{0};
995 mutable std::atomic<size_t> m_needle_smooth_reached{0};
996 mutable std::atomic<size_t> m_needle_smooth_fixed{0};
997 mutable std::atomic<size_t> m_needle_smooth_stationary{0};
998 mutable std::atomic<size_t> m_needle_smooth_reports{0};
999
1002 double ring_max_quality(size_t vid) const;
1004 double tet_amips(const size_t tid) const { return std::cbrt(cell_quality(tid)); }
1005
1013 double tet_flatness(size_t tid) const;
1014
1016 void needle_forensics() const;
1017
1019 void record_flatness(const char* op, double parent_flat, size_t child_tid) const;
1020 mutable std::atomic<size_t> m_flat_created_split{0};
1021 mutable std::atomic<size_t> m_flat_created_collapse{0};
1022 mutable std::atomic<size_t> m_flat_worsened_split{0};
1023 mutable std::atomic<size_t> m_flat_genesis_reports{0};
1024 static constexpr double kFlatThreshold = 1e-3;
1045 double face_resolution_or_inf(size_t a, size_t b, size_t c) const;
1055 std::pair<double, double> ops_guard_measures(
1056 const std::vector<std::array<size_t, 3>>& before,
1057 const std::vector<std::array<size_t, 3>>& after,
1058 size_t removed) const;
1065 double vertex_ring_measure(const std::vector<std::array<size_t, 3>>& ring) const;
1068 double ring_face_area(size_t a, size_t b, size_t c) const;
1074 bool ops_guard_refuses_collapse(size_t v1, size_t v2) const;
1076 std::array<size_t, 3> face_vids(const Tuple& f) const;
1077 void log_smooth_trace() const;
1078
1082 void log_region_face_mask_health(const std::string& when) const;
1083
1086 void audit_surface_containment(const std::string& when) const;
1087
1090 mutable std::atomic<int> m_placement_env_entry_outside{0};
1093 mutable std::atomic<int> m_placement_projected{0};
1096 mutable std::atomic<int> m_placement_tangential{0};
1097
1099
1102 bool vertex_is_on_region(const size_t vid) const
1103 {
1104 return m_vertex_extra[vid].m_is_on_region || !m_vertex_attribute[vid].on_bbox_faces.empty();
1105 }
1106
1108 uint64_t tag_bits(const CellTag& tags) const
1109 {
1110 uint64_t bits = 0;
1111 for (const int64_t t : tags) {
1112 const auto it = m_tag_bit.find(t);
1113 if (it != m_tag_bit.end()) bits |= (uint64_t(1) << it->second);
1114 }
1115 return bits;
1116 }
1117
1122 uint64_t vertex_boundary_mask(const size_t vid) const
1123 {
1124 return vertex_is_on_region(vid) ? m_vertex_extra[vid].m_boundary_mask : uint64_t(0);
1125 }
1126
1129 uint64_t face_mask(const std::array<size_t, 3>& vids) const
1130 {
1131 return vertex_boundary_mask(vids[0]) & vertex_boundary_mask(vids[1]) &
1132 vertex_boundary_mask(vids[2]);
1133 }
1134
1138 uint64_t face_boundary_bits(const Tuple& f) const
1139 {
1140 const std::optional<Tuple> opp = f.switch_tetrahedron(*this);
1141 if (!opp) {
1142 return tag_bits(m_tet_attribute[f.tid(*this)].tag); // domain wall
1143 }
1144 const auto& t0 = m_tet_attribute[f.tid(*this)].tag;
1145 const auto& t1 = m_tet_attribute[opp->tid(*this)].tag;
1146 CellTag diff;
1147 std::set_symmetric_difference(
1148 t0.begin(),
1149 t0.end(),
1150 t1.begin(),
1151 t1.end(),
1152 std::inserter(diff, diff.begin()));
1153 return tag_bits(diff);
1154 }
1155
1159 std::shared_ptr<SampleEnvelope> envelope_for_mask(uint64_t mask) const;
1160
1170 std::shared_ptr<SampleEnvelope> surface_envelope_for_face(
1171 const std::array<size_t, 3>& vids) const override
1172 {
1173 uint64_t mask = face_mask(vids);
1174 bool all_offset = true;
1175 for (const size_t v : vids) {
1176 all_offset = all_offset && m_vertex_extra[v].m_is_on_offset;
1177 }
1178 // The ambiguous case: all corners can be on region boundaries and on the offset surface
1179 // at once. The corner-mask AND is then necessary but not sufficient for the face lying
1180 // on a shared boundary; ask the face's own class, the only record that distinguishes a
1181 // chord from a boundary. Reading the slot is safe here: a split child never reaches
1182 // this branch, and the m_is_surface_fs guard leaves both constraints standing when a
1183 // slot is illegible.
1184 if (mask != 0 && all_offset) {
1185 if (const auto found = try_tuple_from_face(vids)) {
1186 const size_t fid = std::get<1>(*found);
1187 if (m_face_attribute[fid].m_is_surface_fs) {
1188 if (face_is_offset(fid)) {
1189 mask = 0; // an offset face lies on no region boundary
1190 } else {
1191 all_offset = false; // a region face is not the offset surface
1192 }
1193 }
1194 }
1195 }
1196 const std::shared_ptr<SampleEnvelope> base = containment_for(mask, all_offset);
1197 if (base || m_deform_tags.empty()) return base;
1198 // deform_others' ops-only tube: a released boundary is held by no mask -- its vertices
1199 // were freed so smoothing can carry the object -- which would leave the operations free
1200 // to decimate and reposition it. A face the masks and the offset class do not claim, but
1201 // which lies on a released boundary by its incident tets' current tags, is held to the
1202 // tube around the boundary's current shape.
1203 if (const auto found = try_tuple_from_face(vids)) {
1204 if (face_borders_released_boundary(std::get<0>(*found))) return released_envelope();
1205 }
1206 return nullptr;
1207 }
1208
1211 bool allow_surface_swap() const override { return true; }
1212
1222 bool swap_quality_allowed(const double after, const double before, const bool is_surface_flip)
1223 const override
1224 {
1225 const bool ok = after < before;
1226 if (is_surface_flip && m_swap_sides.local().worthwhile) {
1227 ++funnel_quality;
1228 if (ok) ++funnel_quality_ok;
1229 }
1230 return ok;
1231 }
1246 double swap_edge_44_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
1247 override;
1248 double swap_edge_56_energy(const std::vector<std::array<size_t, 4>>& tets, const int op_case)
1249 override;
1250 bool check_surface_topology() const override { return m_offset_params.perform_sanity_checks; }
1251
1259 std::shared_ptr<SampleEnvelope> smoothing_energy_envelope(const size_t vid) const override
1260 {
1261 if (m_vertex_extra[vid].m_is_on_offset && !vertex_is_on_region(vid)) {
1262 return nullptr;
1263 }
1264 const uint64_t mask = vertex_boundary_mask(vid);
1265 if (mask == 0) {
1266 return nullptr;
1267 }
1268 std::shared_ptr<SampleEnvelope> best;
1269 double worst_d2 = -1.;
1270 for (const auto& [tag, env] : m_tag_envelopes) {
1271 const auto it = m_tag_bit.find(tag);
1272 if (it == m_tag_bit.end() || !(mask & (uint64_t(1) << it->second))) continue;
1273 if (!best) {
1274 best = env;
1275 if ((mask & (mask - 1)) == 0) break; // single bit: no violation contest to run
1276 worst_d2 = env->squared_distance(m_vertex_attribute[vid].m_posf);
1277 continue;
1278 }
1279 const double d2 = env->squared_distance(m_vertex_attribute[vid].m_posf);
1280 if (d2 > worst_d2) {
1281 worst_d2 = d2;
1282 best = env;
1283 }
1284 }
1285 return best;
1286 }
1287
1290 std::shared_ptr<SampleEnvelope> smoothing_containment_envelope(const size_t vid) const override
1291 {
1292 return containment_for(vertex_boundary_mask(vid), m_vertex_extra[vid].m_is_on_offset);
1293 }
1294
1300 bool smooth_front_vertex_phase_b(const Tuple& t);
1303 double front_vertex_normal_gradient(size_t vid) const;
1306 Vector3d front_vertex_move_direction(size_t vid) const;
1310 double front_move_alignment(size_t vid) const;
1314 bool front_vertex_alignment_traps_1d_solve(size_t vid) const;
1318 double front_vertex_conv_ratio(size_t vid) const;
1349 bool front_vertex_placed(size_t vid) const;
1353 bool front_placed_by_ratio(const double ratio) const
1354 {
1355 return std::isfinite(ratio) && ratio <= 1.;
1356 }
1359 double edge_conv_ratio(size_t a, size_t b) const;
1371 double face_conv_ratio(size_t a, size_t b, size_t c) const;
1373 static_cast<size_t>(-1);
1375 Vector3d front_vertex_normal(size_t vid) const;
1378 std::shared_ptr<polysolve::nonlinear::Problem> phase_b_front_objective(
1379 size_t vid,
1380 const Vector3d& x) const;
1384 std::shared_ptr<polysolve::nonlinear::Problem> smoothing_extra_energy(
1385 const size_t vid) const override
1386 {
1387 std::shared_ptr<polysolve::nonlinear::Problem> front;
1388 if (phase_places_front() && m_offset_potential && m_vertex_extra[vid].m_is_on_offset &&
1389 vertex_boundary_mask(vid) == 0) {
1390 front = phase_b_front_energy(vid, potential_ptr_for(vid));
1391 }
1392 const std::shared_ptr<polysolve::nonlinear::Problem> rest = rest_energy_for_vertex(vid);
1393 if (!front) return rest;
1394 if (!rest) return front;
1395 auto sum = std::make_shared<optimization::EnergySum>();
1396 sum->add_energy(front);
1397 sum->add_energy(rest);
1398 return sum;
1399 }
1400
1401 // ------- deform_others: other input regions deform instead of being envelope-held -------
1402
1404 std::set<int64_t> m_deform_tags;
1407 std::set<int64_t> m_source_tags;
1412 mutable std::shared_ptr<SampleEnvelope> m_released_envelope;
1413 mutable std::atomic<bool> m_released_tube_dirty{false};
1414 mutable std::mutex m_released_mutex;
1417 std::shared_ptr<SampleEnvelope> released_envelope() const;
1420 bool face_borders_released_boundary(const Tuple& f) const;
1422 bool cell_is_deformable(size_t tid) const;
1428 bool m_plastic_active = false;
1429 bool cell_is_plastic(size_t tid) const
1430 {
1431 // Everything outside the band: ambient, the other objects and the input complex's
1432 // interior alike -- one material. The complex's boundary is what its tube holds.
1433 return m_plastic_active && m_tet_attribute[tid].label != 2;
1434 }
1436 void stamp_plastic_rests();
1438 bool smooth_plastic_vertex(const Tuple& t);
1441 bool cell_is_released_band(size_t tid) const;
1444 void stamp_rest_cell(size_t tid);
1450 std::shared_ptr<polysolve::nonlinear::Problem> rest_energy_for_vertex(size_t vid) const;
1454 std::shared_ptr<polysolve::nonlinear::Problem> phase_b_front_energy(
1455 size_t vid,
1456 const std::shared_ptr<const OffsetPotential3D>& pot) const;
1457
1462 std::tuple<double, double> optimization_quality_stats() override;
1463
1465 double optimization_stop_metric() const override
1466 {
1467 return m_phase != OptPhase::B ? wmtk::TetOptimizerMesh::optimization_stop_metric() : 1.;
1468 }
1469
1471 int stencil_order() const { return m_offset_params.stencil_order; }
1476 {
1477 const int k = m_offset_params.stencil_order;
1478 if (k < 0) return 0;
1479 if (k == 0) return 3;
1480 const int n = 1 << (k - 1);
1481 return (n + 1) * (n + 2) / 2 + n * n;
1482 }
1483
1487 {
1488 const double s = m_offset_potential ? m_offset_potential->level_set_slope() : 1.;
1489 return std::max(0.5 * offset_gradient_tolerance() / (s * s), 1e-16);
1490 }
1491
1497 {
1498 return std::max(m_offset_params.front_conv_frac() * m_gradient_reference, 1e-16);
1499 }
1500
1502 double gradient_reference() const { return m_gradient_reference; }
1503
1506 void check_offset_within_support(const char* when) const;
1507
1511 {
1512 double max_reachable = 0., avg_reachable = 0.;
1513 double max_pinned = 0.;
1514 size_t n_reachable = 0, n_pinned = 0;
1515 double max_at_vertex = 0., max_in_face = 0.;
1516 size_t n_outside_support = 0;
1517 size_t worst_outside_vid = static_cast<size_t>(-1);
1518 double worst_outside_dist = 0.;
1519 };
1520 DistanceSplit distance_deviation_split() const;
1521
1525 std::vector<bool> band_vertex_mask() const;
1526
1529 double max_band_vertex_distance() const;
1531 double band_vertex_distance_error(const size_t vid) const;
1532
1534 double band_vertex_residual(const size_t vid) const;
1535
1538 {
1539 double max = 0.;
1540 double sum = 0.;
1541 size_t n = 0;
1542 };
1543
1559 template <typename Visit>
1561 const Vector3d& p0,
1562 const Vector3d& p1,
1563 const Vector3d& p2,
1564 Visit&& visit) const
1565 {
1566 const int k = m_offset_params.stencil_order;
1567 if (k < 0) return;
1568
1569 const auto emit = [&](const double wa, const double wb, const double wc) {
1570 visit(Vector3d(wa * p0 + wb * p1 + wc * p2), wa, wb, wc);
1571 };
1572 // Order 0 is the three CORNERS alone. That is the whole point of including them: the
1573 // measure sampled here is a distance to the level set, which at a corner is exactly that
1574 // vertex's own placement error, so one stencil covers what used to be two criteria.
1575 if (k == 0) {
1576 emit(1., 0., 0.);
1577 emit(0., 1., 0.);
1578 emit(0., 0., 1.);
1579 return;
1580 }
1581 // Order k >= 1: the vertices of the triangle subdivided k-1 times by 4-way midpoint
1582 // refinement, plus the centroid of each of its 4^(k-1) sub-triangles. With n = 2^(k-1)
1583 // segments per side that is (n+1)(n+2)/2 + n^2 points: 4, 10, 31, 109, ...
1584 const int n = 1 << (k - 1);
1585 const double dn = double(n);
1586 for (int i = n; i >= 0; --i) {
1587 for (int j = n - i; j >= 0; --j) {
1588 emit(double(i) / dn, double(j) / dn, double(n - i - j) / dn);
1589 }
1590 }
1591 // The sub-triangles, in integer barycentric coordinates over 3n. "Up" triangles have
1592 // corners (i+1,j,l), (i,j+1,l), (i,j,l+1) for i+j+l = n-1, so centroid (3i+1, 3j+1,
1593 // 3l+1); "down" triangles (i+1,j+1,l), (i,j+1,l+1), (i+1,j,l+1) for i+j+l = n-2, so
1594 // centroid (3i+2, 3j+2, 3l+2). n(n+1)/2 + n(n-1)/2 = n^2 of them.
1595 const double d3n = 3. * dn;
1596 for (int i = n - 1; i >= 0; --i) {
1597 for (int j = n - 1 - i; j >= 0; --j) {
1598 const int l = n - 1 - i - j;
1599 emit((3. * i + 1.) / d3n, (3. * j + 1.) / d3n, (3. * l + 1.) / d3n);
1600 }
1601 }
1602 for (int i = n - 2; i >= 0; --i) {
1603 for (int j = n - 2 - i; j >= 0; --j) {
1604 const int l = n - 2 - i - j;
1605 emit((3. * i + 2.) / d3n, (3. * j + 2.) / d3n, (3. * l + 2.) / d3n);
1606 }
1607 }
1608 }
1609
1611 template <typename Visit>
1612 void for_each_offset_face_sample(const Tuple& f, Visit&& visit) const
1613 {
1614 const auto vs = get_face_vids(f);
1616 m_vertex_attribute[vs[0]].m_posf,
1617 m_vertex_attribute[vs[1]].m_posf,
1618 m_vertex_attribute[vs[2]].m_posf,
1619 std::forward<Visit>(visit));
1620 }
1621
1625 FaceSamples offset_face_samples(const Tuple& f) const;
1626
1633 {
1634 double max_reachable = 0., avg_reachable = 0.;
1635 double max_pinned = 0.;
1636 size_t n_reachable = 0, n_pinned = 0;
1637 double max_at_vertex = 0., max_in_face = 0.;
1638 double max_in_face_pinned = 0.;
1639 double max_normal_aligned = 0.;
1640 size_t n_face_samples = 0;
1641 size_t n_skipped_inverted = 0, n_skipped_unrounded = 0;
1642 size_t worst_vid = static_cast<size_t>(-1);
1643 };
1645 GradientSplit gradient_split(bool include_face_samples = true) const;
1646
1652 {
1653 double max_vertex = 0., max_face = 0.;
1657 double sum_vertex = 0., sum_face = 0.;
1658 double bar = 1.;
1659 size_t n_vertices = 0, n_faces = 0, n_unmeasurable = 0;
1660 size_t worst_vid = static_cast<size_t>(-1);
1661 Vector3d worst_face_centroid = Vector3d::Zero();
1662 double worst_face_len = 0.;
1668 size_t n_faces_over = 0, n_faces_over_placed = 0;
1669 double max_face_placed = 0.;
1670 Vector3d worst_placed_centroid = Vector3d::Zero();
1671 double tube = 0.;
1677 size_t n_at_floor = 0;
1678 double max_face_at_floor = 0.;
1679 Vector3d worst_at_floor_centroid = Vector3d::Zero();
1687 Vector3d worst_corners_at_floor_centroid = Vector3d::Zero();
1689 double floor_scalar = 0.;
1690 bool floor_from_min_edge_length = false;
1691 size_t n_unplaced = 0;
1700 {
1701 size_t a, b, c;
1702 double measure, len;
1703 };
1704 std::vector<Refinable> refinable;
1726 bool ring_exit = false;
1727 static const char* ring_name() { return "area-weighted ring measure"; }
1728 double max_ring = 0., sum_ring = 0.;
1729 size_t n_rings = 0, n_rings_unmeasurable = 0;
1730 size_t worst_ring_vid = static_cast<size_t>(-1);
1731 size_t n_rings_over = 0;
1734 std::vector<size_t> refinable_vertices;
1738 double max_ring_at_floor = 0.;
1739 Vector3d worst_ring_at_floor_pos = Vector3d::Zero();
1740 bool rings_ok() const { return max_ring <= bar; }
1741 double avg_ring() const { return n_rings ? sum_ring / double(n_rings) : 0.; }
1746 bool vertices_ok() const { return n_unplaced == 0; }
1747 bool faces_ok() const { return max_face <= bar; }
1773 bool converged() const
1774 {
1775 return (ring_exit ? rings_ok() : faces_ok()) && n_unmeasurable == 0;
1776 }
1782 std::string sizing_floor_fact() const;
1783 double ratio() const { return bar > 0. ? std::max(max_vertex, max_face) / bar : 0.; }
1785 double avg_vertex() const { return n_vertices ? sum_vertex / double(n_vertices) : 0.; }
1786 double avg_face() const { return n_faces ? sum_face / double(n_faces) : 0.; }
1787 };
1788 EnergyCriterion energy_criterion();
1795 double front_chord_target(size_t va, size_t vb, double len, double sag, double tube) const;
1796
1800 size_t refine_front_by_halving(const std::vector<EnergyCriterion::Refinable>& faces);
1805 size_t refine_front_by_halving(const std::vector<size_t>& vertices);
1806
1811 void grade_sizing(double grade, const std::vector<size_t>& seeds);
1817 size_t grade_sizing_by_distance(const std::vector<size_t>& seeds);
1818
1822 {
1825 double front_max_ratio = 0.;
1826 size_t front_worst_vid = static_cast<size_t>(-1);
1827 size_t n_front = 0;
1829 double front_max_step = 0.;
1833 size_t background_worst_vid = static_cast<size_t>(-1);
1834 size_t n_background = 0;
1835 };
1837 SmoothingProgress smoothing_progress(const std::vector<Vector3d>& before);
1843 void smooth_group_to_convergence(const char* group_name);
1846 std::optional<EnergyCriterion> m_energy_verdict;
1848 double edge_interpolation_residual(size_t a, size_t b) const;
1849
1852 Vector3d offset_vertex_normal(const size_t vid) const;
1853
1855 void report_outside_support(const char* when, const DistanceSplit& s) const;
1858 bool band_vertex_is_reachable(const size_t vid) const
1859 {
1860 if (m_vertex_extra[vid].m_is_on_offset && vertex_boundary_mask(vid) != 0) return false;
1861 return !vertex_is_on_domain_boundary(vid);
1862 }
1863
1865 size_t refine_sizing_around_worst(double max_metric) override;
1866
1869 void log_stuck_refine_census(double max_metric, double filter_energy);
1870
1873 void log_refine_block_census(const std::string& when, double filter_energy) const;
1874
1876 bool collapse_quality_allowed(size_t v1, double q, double ring_max) const override;
1877
1878 mutable std::atomic<size_t> m_deg_split_created{0};
1879 mutable std::atomic<size_t> m_deg_collapse_offered{0};
1880 mutable std::atomic<size_t> m_deg_collapse_allowed{0};
1881 mutable std::atomic<size_t> m_deg_collapse_by_ringmax{0};
1882 mutable std::atomic<size_t> m_deg_collapse_by_stop{0};
1883 mutable std::atomic<size_t> m_deg_collapse_by_unrounded{0};
1884 std::array<size_t, 6> m_deg_prev_counts{{0, 0, 0, 0, 0, 0}};
1885
1887 void report_needle(const char* op, size_t tid, double parent_q) const;
1888 static constexpr size_t kNeedleReports = 12;
1890 static constexpr double kNeedleQuality = 1e6;
1891 mutable std::atomic<size_t> m_needle_reports{0};
1892
1894 void needle_scan(const char* when) const;
1895
1898 std::set<std::tuple<long, long, long>> m_stuck_prev_cells;
1899 size_t m_stuck_calls = 0;
1900
1904 bool optimization_bare_coarsen_passes() const override { return false; }
1905
1908 double face_criterion_rel(const Tuple& f) const;
1910 double cell_quality_rel(const size_t tid) const;
1912 double amips_rel_at_face(const Tuple& f) const;
1913
1919 void write_optimization_debug_output(const std::string& path) override
1920 {
1921 const char ph = (m_phase == OptPhase::A) ? 'A' : (m_phase == OptPhase::B ? 'B' : 'S');
1922 if (m_ab_round != m_debug_last_round || ph != m_debug_last_phase) {
1923 m_debug_last_round = m_ab_round;
1924 m_debug_last_phase = ph;
1925 m_debug_pass = 0;
1926 }
1927 std::string label = path;
1928 if (path.rfind("debug_", 0) == 0) {
1929 label = fmt::format(
1930 "r{}{}{}{}",
1931 m_ab_round,
1932 ph,
1933 ++m_debug_pass,
1934 m_debug_pass_name.empty() ? std::string() : "_" + m_debug_pass_name);
1935 } else if (path.rfind("phase_", 0) == 0) {
1936 label = fmt::format("r{}{}_end", m_ab_round, ph);
1937 }
1938 write_debug_frame(label);
1939 }
1941 void append_frame_label(size_t idx, const std::string& label) const;
1951 void write_debug_frame(const std::string& label);
1952
1961 void init_from_image(
1962 const MatrixXd& V,
1963 const MatrixXi& T,
1964 const MatrixSi& T_tags,
1965 const MatrixXd& V_env,
1966 const MatrixXi F_env,
1967 const std::vector<std::string>& tag_names,
1968 const std::string& sheet_name = "");
1969
1971 bool ambient_assert();
1972
1974 void label_input_complex();
1975
1977 bool empty_input_complex();
1978
1985
1987 void init_offset_potential();
1988
1992 MatrixXd m_phi_V;
1993 MatrixXi m_phi_E;
1994 MatrixXi m_phi_F;
1995 std::vector<int> m_phi_P;
1996
1998 size_t flood_fill();
1999
2000 std::vector<std::array<size_t, 3>> get_faces_by_condition(
2001 std::function<bool(const FaceAttributes&)> cond) const;
2002
2004 bool split_edge_before(const Tuple& t) override;
2005 bool split_edge_after(const Tuple& t) override;
2006 bool split_face_before(const Tuple& t) override;
2007 bool split_face_after(const Tuple& t) override;
2008 bool split_tet_before(const Tuple& t) override;
2009 bool split_tet_after(const Tuple& t) override;
2010 bool invariants(const std::vector<Tuple>& tets) override;
2012
2016 void execute_offset(const std::filesystem::path& output_file);
2017
2023 void marching_tets();
2024
2026 bool is_simplicially_embedded() const;
2027 bool tet_is_simp_emb(const Tuple& t) const;
2028 void simplicial_embedding();
2030
2032 void set_offset_tet_tags();
2033
2035 bool offset_is_manifold();
2036
2040 void write_phi_grid(const std::string& path, int n) const;
2041
2042 void write_input_complex(const std::string& path);
2043 void write_vtu(const std::string& path);
2044 void write_msh_groups(const std::string& file);
2046
2047private:
2054 {
2055 size_t v1_id;
2056 size_t v2_id;
2057 Vector3d new_v_pos;
2058 VertexExtra new_v_extra;
2059
2060 bool is_edge_on_region = false;
2061 bool is_edge_on_offset = false;
2062 bool is_edge_open_boundary = false;
2063
2064 std::vector<std::pair<FaceAttributes, std::array<size_t, 3>>> changed_faces;
2065
2066 // cache edge attributes
2067 EdgeAttributes split_e;
2068 std::map<size_t, EdgeAttributes> internal_e;
2069 std::map<simplex::Edge, EdgeAttributes> external_e; // edge is boundary edge (not link)
2070 std::map<simplex::Edge, EdgeAttributes> link_e; // link edge around splitted edge
2071
2072 // cache face attributes
2073 std::map<size_t, FaceSnapshot> split_f; // splitted faces
2074 std::map<simplex::Edge, FaceSnapshot> internal_f; // new faces created by split
2075 std::map<std::pair<simplex::Edge, size_t>, FaceSnapshot>
2076 external_f; // closed star boundary faces of splitted edge
2077
2078 // cache tet attributes
2079 std::map<simplex::Edge, TetAttributes> tets;
2080 };
2082
2084 {
2085 size_t v1_id;
2086 size_t v2_id;
2087 size_t v3_id;
2088 std::map<simplex::Edge, EdgeAttributes> existing_e;
2089 std::map<simplex::Face, FaceSnapshot> existing_f;
2090 int splitf_label;
2091 std::map<size_t, TetAttributes> tets;
2092 };
2094
2096 {
2097 std::array<size_t, 4> v_ids;
2098 std::map<simplex::Edge, EdgeAttributes> existing_e;
2099 std::map<simplex::Face, FaceSnapshot> existing_f;
2100 TetAttributes tet;
2101 };
2103
2114 bool swap_capture_tag(const std::vector<size_t>& tids);
2119
2132 {
2133 std::map<size_t, std::pair<CellTag, int>> by_vertex;
2137 std::array<size_t, 4> abcd{};
2143 bool sag_measured = false;
2144 double sag_before = 0.0;
2145 double sag_after = 0.0;
2148 bool worthwhile = false;
2151 double case0_energy = 0.0;
2156 bool saw_case = false;
2158 int kind = 0;
2159 };
2160 bool swap_capture_surface_sides(
2161 const std::vector<size_t>& tids,
2162 size_t a,
2163 size_t b,
2164 size_t c,
2165 size_t d);
2169
2170public:
2171 // substructure functions
2172
2173 bool is_order_2_edge(const Tuple& e) const;
2174 bool is_order_2_edge(const std::array<size_t, 2>& e) const;
2175
2176 bool vertex_is_on_surface(const size_t vid) const override;
2177
2178 bool face_is_on_surface(const size_t fid) const override;
2179
2180 size_t get_order_of_vertex(const size_t vid) const override;
2182 void init_vertex_order();
2183
2184private: // helpers
2189 bool any_tag_present(const CellTag& tag1, const CellTag& tag2)
2190 {
2191 if (tag2.empty()) {
2192 return tag1.empty();
2193 }
2194 if (tag1.empty()) { // tag1 is ambient, tag2 is not
2195 return false;
2196 }
2197
2198 for (const int64_t& i : tag1) {
2199 if (tag2.find(i) != tag2.end()) {
2200 return true;
2201 }
2202 }
2203 return false;
2204 }
2205
2207 void sort_edges_by_length(std::vector<simplex::Edge>& edges)
2208 {
2209 std::sort(
2210 edges.begin(),
2211 edges.end(),
2212 [this](const simplex::Edge& e1, const simplex::Edge& e2) {
2213 double len1 = (m_vertex_attribute[e1.vertices()[0]].m_posf -
2214 m_vertex_attribute[e1.vertices()[1]].m_posf)
2215 .norm();
2216 double len2 = (m_vertex_attribute[e2.vertices()[0]].m_posf -
2217 m_vertex_attribute[e2.vertices()[1]].m_posf)
2218 .norm();
2219 return len1 > len2;
2220 });
2221 }
2222
2223public: // helpers
2226
2227 size_t get_partition_id(const Tuple& loc) const
2228 {
2229 return m_vertex_attribute[loc.vid(*this)].partition_id;
2230 }
2231
2233 std::vector<size_t> connected_components_helper(const size_t& v_id)
2234 {
2235 auto onering_v_ids = get_one_ring_vids_for_vertex(v_id);
2236 std::vector<size_t> ret_v_ids;
2237 for (const size_t& other_v_id : onering_v_ids) {
2238 size_t e_id = tuple_from_edge({{v_id, other_v_id}}).eid(*this);
2239 if (m_edge_attribute[e_id].label != 0) { // edge labelled 1 or 2
2240 ret_v_ids.push_back(other_v_id);
2241 }
2242 }
2243 return ret_v_ids;
2244 }
2245
2248 {
2249 auto verts = get_vertices();
2250 for (const Tuple& v : verts) {
2251 size_t v_id = v.vid(*this);
2252 m_vertex_extra[v_id].component_id = 0;
2253 }
2254 }
2255};
2256
2257
2258} // namespace wmtk::components::topological_offset
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
std::optional< Tuple > switch_tetrahedron(const TetMesh &m) const
Definition TetMeshTuple.cpp:304
size_t tid(const TetMesh &m) const
Definition TetMeshTuple.cpp:250
std::optional< std::tuple< Tuple, size_t > > try_tuple_from_face(const std::array< size_t, 3 > &vids) const
tuple_from_face for callers where a missing face is an answer, not a bug.
Definition TetMesh.cpp:430
std::vector< size_t > get_one_ring_vids_for_vertex(size_t vid, std::vector< size_t > &cache)
Get the one ring vids for vertex.
Definition TetMesh.cpp:800
Tuple tuple_from_edge(size_t tid, int local_eid) const
get a Tuple from global tetra index and local edge index (from 0-5).
Definition TetMesh.cpp:342
std::vector< Tuple > get_vertices() const
Definition TetMesh.cpp:311
What tetwild and simwild's 3D mesh share.
Definition TetOptimizerMesh.h:46
AttributeContainerGroup m_vertex_attr_group
What p_vertex_attrs points at, so a derived class can register more.
Definition TetOptimizerMesh.h:93
std::string m_debug_pass_name
Definition TetOptimizerMesh.h:247
AttributeContainerGroup m_face_attr_group
What p_face_attrs points at, so a derived class can register more.
Definition TetOptimizerMesh.h:108
Definition TopoOffsetTetMesh.h:94
bool on_sheet
Definition TopoOffsetTetMesh.h:101
The offset potential: the scalar field on space whose level set the front is placed on.
Definition OffsetPotential.hpp:37
Definition TopoOffsetTetMesh.h:106
bool rest_valid
Definition TopoOffsetTetMesh.h:117
The offset's tet mesh, on the shared 3D optimizer.
Definition TopoOffsetTetMesh.h:136
void stamp_plastic_rests()
Stamp rest := current for every plastic cell; called before every operation group.
Definition Optimize3d.cpp:564
double ring_face_area(size_t a, size_t b, size_t c) const
Definition Optimize3d.cpp:1060
wmtk::threading::enumerable_thread_specific< double > m_collapse_parent_flatness
The flattest tet in the collapse's ring before it ran, for record_flatness().
Definition TopoOffsetTetMesh.h:1026
std::vector< std::array< int, 3 > > churn_counts
Definition TopoOffsetTetMesh.h:666
EnvelopeSetup
Which boundaries the region-class envelopes hold, and how they are built.
Definition TopoOffsetTetMesh.h:355
int64_t m_sheet_tag
Definition TopoOffsetTetMesh.h:153
double front_chord_target(size_t va, size_t vb, double len, double sag, double tube) const
Definition Optimize3d.cpp:3329
std::atomic< int > iter_cnt_split_born
Definition TopoOffsetTetMesh.h:703
double vertex_ring_measure(const std::vector< std::array< size_t, 3 > > &ring) const
Definition Optimize3d.cpp:1068
int stencil_points_per_face() const
Definition TopoOffsetTetMesh.h:1475
bool vertex_is_on_domain_boundary(const size_t vid) const
Identification only – no operation refuses the domain wall through these.
Definition TopoOffsetTetMesh.h:896
bool split_edge_after(const Tuple &t) override
This function computes the attributes for the added simplices. User specified modifications and desid...
Definition EdgeSplittingTet.cpp:238
void report_offset_face_lookup_misses(const char *when) const
Definition Optimize3d.cpp:4081
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 Optimize3d.cpp:713
OptPhase m_phase
Which phase is running. Read by every hook that differs between them; see OptPhase.
Definition TopoOffsetTetMesh.h:332
std::set< int64_t > m_source_tags
Definition TopoOffsetTetMesh.h:1407
std::atomic< int > iter_cnt_collapse_offset_reject
Operations refused because they would have left an offset-surface face over tolerance.
Definition TopoOffsetTetMesh.h:709
MatrixXd m_phi_V
Definition TopoOffsetTetMesh.h:1992
size_t m_worst_dist_vid
Definition TopoOffsetTetMesh.h:560
bool smooth_plastic_vertex(const Tuple &t)
The plastic vertex's smoothing: rest-shape AMIPS over its ring, nothing else.
Definition Optimize3d.cpp:579
size_t grade_sizing_by_distance(const std::vector< size_t > &seeds)
Definition Optimize3d.cpp:3497
wmtk::threading::enumerable_thread_specific< SwapSurfaceSides > m_swap_sides
Definition TopoOffsetTetMesh.h:2168
double optimization_stop_metric() const override
stop_energy outside Phase B, 1.0 in it – in the same units as the line above.
Definition TopoOffsetTetMesh.h:1465
std::shared_ptr< const OffsetPotential3D > potential_ptr_for(const size_t vid) const
Definition TopoOffsetTetMesh.h:251
std::tuple< double, double > optimization_quality_stats() override
The loop's quality metric: TetWild's own outside Phase B, the max of AMIPS and the Phi residual (each...
Definition Optimize3d.cpp:3674
uint64_t face_boundary_bits(const Tuple &f) const
Definition TopoOffsetTetMesh.h:1138
int m_debug_pass
Definition TopoOffsetTetMesh.h:686
std::optional< EnergyCriterion > m_energy_verdict
Definition TopoOffsetTetMesh.h:1846
void record_flatness(const char *op, double parent_flat, size_t child_tid) const
Genesis: flatness transitions recorded at the operation hooks. {op, parent, child}.
Definition Optimize3d.cpp:2436
std::atomic< long long > funnel_cases
Definition TopoOffsetTetMesh.h:758
FaceSamples offset_face_samples(const Tuple &f) const
Definition Optimize3d.cpp:2620
bool cell_is_offset_band(const size_t tid) const
Whether tet tid is part of the offset BAND (as opposed to the input complex).
Definition TopoOffsetTetMesh.h:545
std::atomic< long long > flip_trace_bar
Definition TopoOffsetTetMesh.h:729
void report_outside_support(const char *when, const DistanceSplit &s) const
Turn a residual_split()'s outside-support tally into the hard error.
Definition Optimize3d.cpp:3607
wmtk::threading::enumerable_thread_specific< double > m_collapse_survivor_sizing
Definition TopoOffsetTetMesh.h:1029
void sort_edges_by_length(std::vector< simplex::Edge > &edges)
sort edge simplices in place by decreasing edge length
Definition TopoOffsetTetMesh.h:2207
wmtk::threading::enumerable_thread_specific< int > m_swap_label
The construction label shared by every cell of an interior swap's ring, captured alongside.
Definition TopoOffsetTetMesh.h:2118
std::map< uint64_t, std::shared_ptr< SampleEnvelope > > m_offset_isect_cache
Memoized "region tubes AND the offset envelope", keyed by the region mask.
Definition TopoOffsetTetMesh.h:294
std::shared_ptr< SampleEnvelope > smoothing_energy_envelope(const size_t vid) const override
The offset surface is the one tracked surface with no envelope, in either role.
Definition TopoOffsetTetMesh.h:1259
void write_debug_frame(const std::string &label)
One frame of the run's single debug timeline: <output>_NNNNN.vtu with the next sequence number,...
Definition Optimize3d.cpp:4397
std::atomic< int > m_placement_tangential
Definition TopoOffsetTetMesh.h:1096
std::vector< int > m_cell_region
per tet: band's region, -1 none, -2 reached from two
Definition TopoOffsetTetMesh.h:222
uint64_t face_mask(const std::array< size_t, 3 > &vids) const
Definition TopoOffsetTetMesh.h:1129
std::string envelope_key_name(int64_t tag) const
The name a tag or pseudo-tag prints under.
Definition TopoOffsetTetMesh.cpp:271
void for_each_offset_face_sample(const Tuple &f, Visit &&visit) const
The same lattice over a face the mesh carries. Visitor signature as above.
Definition TopoOffsetTetMesh.h:1612
std::vector< std::array< size_t, 2 > > offset_surface_edges() const
Definition Optimize3d.cpp:3962
void build_boundary_envelopes(const char *when, EnvelopeSetup setup)
Definition TopoOffsetTetMesh.cpp:291
std::vector< char > offset_surface_foldover_labels() const
Per-vertex 0/1: is this vertex an endpoint of a COLLAPSED (folded-over) offset surface edge?...
Definition Optimize3d.cpp:4105
void release_deformable_regions()
Definition Optimize3d.cpp:632
double edge_conv_ratio(size_t a, size_t b) const
Definition Optimize3d.cpp:3106
size_t get_order_of_vertex(const size_t vid) const override
Get the order of a vertex.
Definition TopoOffsetTetMesh.cpp:1172
void reset_connected_components()
reset connected component assignments.
Definition TopoOffsetTetMesh.h:2247
bool front_vertex_placed(size_t vid) const
THE definition of "placed" for a vertex on the offset surface.
Definition Optimize3d.cpp:3099
size_t flood_fill()
label connected simplicial complex components (simplices labelled 1 or 2)
Definition TopoOffsetTetMesh.cpp:1116
void grade_sizing(double grade, const std::vector< size_t > &seeds)
Definition Optimize3d.cpp:3487
std::vector< int64_t > m_phi_vert_region
per m_phi_V row: region index
Definition TopoOffsetTetMesh.h:218
void write_debug_pvd() const
Definition Optimize3d.cpp:4421
bool split_after_cells(size_t v1, size_t v2, size_t v_new, const std::vector< Tuple > &children) override
Restore application cell data on the children made by a split.
Definition EdgeSplittingTet.cpp:636
std::vector< bool > band_vertex_mask() const
Which vertices lie on the band's outer surface. Shared by every measurement.
Definition Optimize3d.cpp:2599
std::shared_ptr< SampleEnvelope > envelope_for_mask(uint64_t mask) const
Definition Optimize3d.cpp:424
bool cell_is_deformable(size_t tid) const
Under deform_others the same set as cell_is_plastic(): every cell outside the band.
Definition Optimize3d.cpp:532
void label_offset_boundary()
Tag the two tracked surfaces for the optimization phase.
Definition Optimize3d.cpp:155
std::array< std::atomic< long long >, 3 > funnel_kind
offered, split by swap kind: [0] = 3-2, [1] = 4-4, [2] = 5-6.
Definition TopoOffsetTetMesh.h:755
double offset_gradient_tolerance() const
Definition TopoOffsetTetMesh.h:1496
bool cell_in_region(const size_t tid) const
Definition TopoOffsetTetMesh.h:537
bool collapse_edge_before(const Tuple &t) override
Reject any collapse that violates the substructure link condition, and remember the survivor's sizing...
Definition Optimize3d.cpp:882
static bool & split_off_longest()
Definition TopoOffsetTetMesh.h:782
void marching_tets()
Definition TopoOffsetTetMesh.cpp:1444
static constexpr long long kFlipTraceEvery
Definition TopoOffsetTetMesh.h:725
bool smooth_before(const Tuple &t) override
User specified preparations and desideratas for smoothing a vertex.
Definition Optimize3d.cpp:1276
bool split_edge_before(const Tuple &t) override
User specified preparations and desideratas for an edge split before changing the connectivity.
Definition EdgeSplittingTet.cpp:12
std::shared_ptr< OffsetPotential3D > m_offset_potential
The smooth offset potential, and with it the definition of the offset itself.
Definition TopoOffsetTetMesh.h:189
void init_offset_potential()
Build the smooth offset potential from the extraction init_input_complex_bvh() kept.
Definition TopoOffsetTetMesh.cpp:990
void set_offset_tet_tags()
update 'tags' data for tets in the offset region (tets labelled 2)
Definition TopoOffsetTetMesh.cpp:1583
bool split_tet_after(const Tuple &t) override
Compute the attributes for the added simplices.
Definition EdgeSplittingTet.cpp:542
std::shared_ptr< SimplicialComplexBVH > m_input_complex_bvh
The input complex as loaded. Built once, never rebuilt.
Definition TopoOffsetTetMesh.h:179
std::shared_ptr< polysolve::nonlinear::Problem > phase_b_front_objective(size_t vid, const Vector3d &x) const
Definition FrontSmooth3d.cpp:434
bool face_is_on_surface(const size_t fid) const override
Is a face part of the substructure.
Definition Optimize3d.cpp:150
bool ambient_assert()
check that the ambient tag does not overlap with any other tags
Definition TopoOffsetTetMesh.cpp:403
void log_front_profile(size_t vid)
Diagnostic: the front objective of one vertex along its normal, offset term vs total.
Definition Optimize3d.cpp:3290
std::atomic< long long > flip_trace_nonmono
fall < 0 (a rise): MUST stay 0, the rule forbids it
Definition TopoOffsetTetMesh.h:727
std::vector< Tuple > offset_surface_faces_live_at(size_t vid) const
The live offset-surface faces incident to vid.
Definition Optimize3d.cpp:3990
MatrixXd m_sheet_V
The surface group as loaded, kept because the classification below is redone on demand.
Definition TopoOffsetTetMesh.h:155
std::shared_ptr< SampleEnvelope > m_input_complex_envelope
The exact-kind envelope of the input complex, built only for offset_field "euclidean"....
Definition TopoOffsetTetMesh.h:200
static constexpr int64_t m_complex_tag
Definition TopoOffsetTetMesh.h:361
void compute_vertex_partition()
assign each vertex a partition id (by spatial Morton order). A no-op if NUM_THREADS == 0.
Definition TopoOffsetTetMesh.cpp:1191
Vector3d offset_vertex_normal(const size_t vid) const
Definition Optimize3d.cpp:1395
double face_conv_ratio(size_t a, size_t b, size_t c) const
Definition Optimize3d.cpp:3126
double amips_rel_at_face(const Tuple &f) const
... and the worst of the (up to two) cells a face separates.
Definition Optimize3d.cpp:3703
double max_band_vertex_distance() const
Definition TopoOffsetTetMesh.cpp:1225
std::vector< std::string > m_debug_frame_labels
Definition TopoOffsetTetMesh.h:677
double offset_residual_tolerance() const
Definition TopoOffsetTetMesh.h:1486
void mark_input_complex_vertices()
Definition TopoOffsetTetMesh.cpp:388
std::atomic< int > iter_cnt_split_offset_before
Splits of an offset-surface edge: offered, accepted.
Definition TopoOffsetTetMesh.h:773
static constexpr int INPUT_SURFACE_CLASS
SurfaceTagAttributes::m_surface_class: which of the two tracked surfaces a face belongs to....
Definition TopoOffsetTetMesh.h:429
bool cell_is_input_complex(const size_t tid) const
Whether tet tid is part of the INPUT complex the band wraps.
Definition TopoOffsetTetMesh.h:543
wmtk::threading::enumerable_thread_specific< std::vector< size_t > > m_collapse_edge_link
The link of the collapsed edge, captured in collapse_before_vertex().
Definition TopoOffsetTetMesh.h:1042
void check_offset_membership(const char *when) const
Definition Optimize3d.cpp:4060
bool face_borders_released_boundary(const Tuple &f) const
Definition Optimize3d.cpp:4224
wmtk::threading::enumerable_thread_specific< std::pair< double, Vector3d > > m_needle_pre
Why smoothing does not repair a sliver in its one-ring. Same counters as 2D: offered / reached / fixe...
Definition TopoOffsetTetMesh.h:993
std::shared_ptr< SampleEnvelope > smoothing_containment_envelope(const size_t vid) const override
Definition TopoOffsetTetMesh.h:1290
bool marching_split_edge_after(const Tuple &t)
Definition EdgeSplittingTet.cpp:251
double gradient_reference() const
The scale offset_gradient_tolerance() is a fraction of; 0 on the single-phase path.
Definition TopoOffsetTetMesh.h:1502
bool vertex_has_live_offset_face(size_t vid) const
Definition Optimize3d.cpp:4014
bool face_is_offset(const size_t fid) const
Definition TopoOffsetTetMesh.h:493
std::atomic< int > m_placement_projected
Definition TopoOffsetTetMesh.h:1093
bool split_face_before(const Tuple &t) override
User specified preparations and desideratas for a face split before changing the connectivity.
Definition EdgeSplittingTet.cpp:344
const OffsetPotential3D & potential_for_face(const Tuple &f) const
The field of the band cell a live offset face belongs to.
Definition Optimize3d.cpp:4173
std::vector< std::shared_ptr< SimplicialComplexBVH > > m_region_bvhs
Definition TopoOffsetTetMesh.h:217
Parameters & m_offset_params
The base holds only wmtk::OptimizerParameters; this is the same object, typed.
Definition TopoOffsetTetMesh.h:433
bool m_quality_converged
Definition TopoOffsetTetMesh.h:698
void init_from_image(const MatrixXd &V, const MatrixXi &T, const MatrixSi &T_tags, const MatrixXd &V_env, const MatrixXi F_env, const std::vector< std::string > &tag_names, const std::string &sheet_name="")
initialize TetMesh from vertex, tet, and tag data
Definition TopoOffsetTetMesh.cpp:73
std::shared_ptr< SampleEnvelope > containment_for(uint64_t region_mask, bool on_offset) const
The containment a simplex with this region mask, on/off the offset surface, must satisfy – the inters...
Definition Optimize3d.cpp:463
bool offset_is_manifold()
verify that the closed offset region (simplices labelled 1 or 2) form a manifold region.
Definition TopoOffsetTetMesh.cpp:1617
void audit_surface_containment(const std::string &when) const
Definition Optimize3d.cpp:1422
double front_vertex_conv_ratio(size_t vid) const
Definition Optimize3d.cpp:3076
static constexpr int64_t m_wall_tag
pseudo-tag: the domain wall's tube
Definition TopoOffsetTetMesh.h:360
void log_refine_block_census(const std::string &when, double filter_energy) const
Definition Optimize3d.cpp:1896
uint64_t vertex_boundary_mask(const size_t vid) const
Definition TopoOffsetTetMesh.h:1122
void write_optimization_debug_output(const std::string &path) override
Put the optimization's frames on the run's single debug timeline (see write_debug_frame()),...
Definition TopoOffsetTetMesh.h:1919
void init_vertex_order()
Compute the vertex order for every vertex.
Definition TopoOffsetTetMesh.cpp:1177
void needle_forensics() const
The full post-mortem on why nothing removes the flat cells; see the 2D twin.
Definition Optimize3d.cpp:2486
void append_frame_label(size_t idx, const std::string &label) const
One line of <output>_frames.txt; truncates the file on the first frame.
Definition Optimize3d.cpp:4389
double band_vertex_distance_error(const size_t vid) const
|dist(vid, input complex) - target_distance|. Diagnostic: the Euclidean offset.
Definition Optimize3d.cpp:2609
std::atomic< long long > funnel_offered
[flip funnel]: of the flips of the offset surface that passed the sag rule, how many survive each lat...
Definition TopoOffsetTetMesh.h:753
void execute_offset(const std::filesystem::path &output_file)
Definition TopoOffsetTetMesh.cpp:1245
bool any_tag_present(const CellTag &tag1, const CellTag &tag2)
determine if any tag from tag1 is also present in tag2.
Definition TopoOffsetTetMesh.h:2189
std::atomic< long > m_split_order_waits
Definition TopoOffsetTetMesh.h:778
bool is_edge_on_region(const Tuple &loc)
Definition Optimize3d.cpp:89
double tet_amips(const size_t tid) const
AMIPS of one tet, the cube root of cell_quality(); the number every log line reports.
Definition TopoOffsetTetMesh.h:1004
bool project_into_containment(size_t vid, Vector3d &x) const
Move x back inside every region tube this vertex lies on. True if it ended up inside all of them....
Definition Optimize3d.cpp:492
bool band_vertex_is_reachable(const size_t vid) const
Definition TopoOffsetTetMesh.h:1858
std::pair< double, double > ops_guard_measures(const std::vector< std::array< size_t, 3 > > &before, const std::vector< std::array< size_t, 3 > > &after, size_t removed) const
Definition Optimize3d.cpp:997
std::vector< std::shared_ptr< OffsetPotential3D > > m_region_potentials
Definition TopoOffsetTetMesh.h:213
std::shared_ptr< SampleEnvelope > m_offset_envelope
The tube the offset surface may not leave during the operation passes, of half-width offset_envelope....
Definition TopoOffsetTetMesh.h:381
size_t m_front_gradient_worst_vid
Definition TopoOffsetTetMesh.h:1372
void set_vertex_position(const size_t vid, const Vector3d &p)
Place a vertex, keeping its exact and rounded coordinates in step.
Definition TopoOffsetTetMesh.h:483
std::shared_ptr< polysolve::nonlinear::Problem > smoothing_extra_energy(const size_t vid) const override
Definition TopoOffsetTetMesh.h:1384
std::vector< size_t > connected_components_helper(const size_t &v_id)
all one-ring vertices through input simplices (labelled 1 or 2)
Definition TopoOffsetTetMesh.h:2233
std::atomic< int > m_placement_env_entry_outside
Definition TopoOffsetTetMesh.h:1090
std::map< int64_t, std::shared_ptr< SampleEnvelope > > m_tag_envelopes
One containment envelope per input tag, ambient included. Both phases.
Definition TopoOffsetTetMesh.h:276
std::set< int64_t > m_deform_tags
The released tags. Filled by release_deformable_regions(); empty = feature inactive.
Definition TopoOffsetTetMesh.h:1404
bool collapse_before_vertex(size_t v1, size_t v2, double edge_length) override
Definition Optimize3d.cpp:1091
uint64_t tag_bits(const CellTag &tags) const
The three helpers of the per-tag envelope dispatch.
Definition TopoOffsetTetMesh.h:1108
std::vector< int > m_vertex_region
per vertex: region of its band cells, -1 / -2 as above
Definition TopoOffsetTetMesh.h:223
std::shared_ptr< polysolve::nonlinear::Problem > phase_b_front_energy(size_t vid, const std::shared_ptr< const OffsetPotential3D > &pot) const
Definition FrontSmooth3d.cpp:489
bool front_vertex_alignment_traps_1d_solve(size_t vid) const
Definition FrontSmooth3d.cpp:398
Vector3d front_vertex_move_direction(size_t vid) const
Definition FrontSmooth3d.cpp:331
void log_smoothing_pass_accounting() override
Definition Optimize3d.cpp:1836
void warn_if_offset_reaches_domain_boundary() const
Warn if the offset band has grown into the domain boundary.
Definition Optimize3d.cpp:391
std::shared_ptr< SampleEnvelope > released_envelope() const
Definition Optimize3d.cpp:4247
void stamp_rest_cell(size_t tid)
Definition Optimize3d.cpp:555
double edge_interpolation_residual(size_t a, size_t b) const
The interpolation residual of front edge (a, b), see EnergyCriterion. -1 unmeasurable.
Definition Optimize3d.cpp:2776
bool m_freeze_front
The final Phase A: front vertices are not smoothed (see smooth_before()).
Definition TopoOffsetTetMesh.h:335
double band_vertex_residual(const size_t vid) const
How far vid is from the level set Phi = c, as a length.
Definition Optimize3d.cpp:2615
std::set< std::tuple< long, long, long > > m_stuck_prev_cells
Definition TopoOffsetTetMesh.h:1898
std::pair< size_t, size_t > offset_membership_mismatches() const
Definition Optimize3d.cpp:4047
void refresh_offset_membership(size_t vid)
Re-derive m_is_on_offset for one vertex from the cell labels, exactly.
Definition Optimize3d.cpp:4042
bool optimization_bare_coarsen_passes() const override
Definition TopoOffsetTetMesh.h:1904
void assign_band_regions(bool log=true)
Definition Optimize3d.cpp:3191
std::vector< int64_t > m_phi_seg_region
per m_phi_E row: region index, -1 unknown
Definition TopoOffsetTetMesh.h:219
double front_move_alignment(size_t vid) const
Definition FrontSmooth3d.cpp:317
void init_input_complex_bvh()
Build the input complex's BVH and keep the extraction the potential needs, and number the complex's c...
Definition TopoOffsetTetMesh.cpp:715
std::atomic< int > iter_cnt_collapse_guard_reject
Definition TopoOffsetTetMesh.h:713
double phase_b_front_gradient_linf()
Definition Optimize3d.cpp:3056
std::shared_ptr< SampleEnvelope > surface_envelope_for_face(const std::array< size_t, 3 > &vids) const override
Class-0 faces – every region boundary, the input complex and the domain wall included – carry a conta...
Definition TopoOffsetTetMesh.h:1170
double swap_edge_44_energy(const std::vector< std::array< size_t, 4 > > &tets, const int op_case) override
Counting only: the scored cases of a 4-4 / 5-6 flip of the offset surface, for [flip funnel]....
Definition Optimize3d.cpp:685
bool allow_surface_swap() const override
Definition TopoOffsetTetMesh.h:1211
bool is_open_boundary_edge(const Tuple &e) override
Definition TopoOffsetTetMesh.h:883
bool swap_before_interior(const std::vector< size_t > &tids) override
Which tag the tets a swap creates should carry, and the topology half of the surface-flip refusal (cl...
Definition Optimize3d.cpp:270
bool front_placed_by_ratio(const double ratio) const
Definition TopoOffsetTetMesh.h:1353
void label_input_complex()
label input simplicial complex simplices, as defined in m_offset_params.offset_selection
Definition TopoOffsetTetMesh.cpp:460
void smooth_group_to_convergence(const char *group_name)
Definition Optimize3d.cpp:3440
std::pair< double, double > compute_distance_deviation() const
How far the offset surface is from where it should be: {max, avg} over vertices.
Definition Optimize3d.cpp:3628
bool collapse_quality_allowed(size_t v1, double q, double ring_max) const override
Instrumentation only: which operation manufactures the MAX_ENERGY needles.
Definition Optimize3d.cpp:2283
void split_after_vertex(size_t v_new, bool is_edge_open_boundary) override
Application metadata not represented by the shared vertex attributes.
Definition Optimize3d.cpp:1232
void rebuild_offset_envelope()
Definition Optimize3d.cpp:4283
void for_each_face_sample(const Vector3d &p0, const Vector3d &p1, const Vector3d &p2, Visit &&visit) const
The interior lattice a triangle is sampled on, handed to visit one point at a time as (point,...
Definition TopoOffsetTetMesh.h:1560
std::map< uint64_t, std::shared_ptr< SampleEnvelope > > m_isect_cache
Definition TopoOffsetTetMesh.h:284
std::vector< std::array< int, 3 > > op_counts
{splits, collapses, swaps} per turn, as deltas rather than running totals.
Definition TopoOffsetTetMesh.h:668
static constexpr double kNeedleQuality
What counts as a needle for the tripwire, in AMIPS – deliberately far below MAX_ENERGY.
Definition TopoOffsetTetMesh.h:1890
bool m_converged
Definition TopoOffsetTetMesh.h:694
size_t refine_front_by_halving(const std::vector< EnergyCriterion::Refinable > &faces)
Definition Optimize3d.cpp:3363
double face_resolution_or_inf(size_t a, size_t b, size_t c) const
Definition Optimize3d.cpp:914
bool smooth_front_vertex_phase_b(const Tuple &t)
Phase B placement of a front vertex: the shared smoother with the offset's options,...
Definition FrontSmooth3d.cpp:199
GradientSplit gradient_split(bool include_face_samples=true) const
Definition Optimize3d.cpp:2683
bool edge_is_offset_surface_live(size_t a, size_t b) const
Whether edge (a, b) lies on the band's outer surface: some incident face does.
Definition Optimize3d.cpp:3949
bool swap_capture_tag(const std::vector< size_t > &tids)
Definition Optimize3d.cpp:236
bool swap_quality_allowed(const double after, const double before, const bool is_surface_flip) const override
Definition TopoOffsetTetMesh.h:1222
SmoothingProgress smoothing_progress(const std::vector< Vector3d > &before)
Measure a pass: before holds every live vertex's position before it, indexed by vid.
Definition Optimize3d.cpp:3398
std::array< std::atomic< long long >, 8 > flip_trace_dec
Definition TopoOffsetTetMesh.h:732
bool face_is_complex_boundary(const Tuple &f) const
Definition TopoOffsetTetMesh.cpp:279
DistanceSplit residual_split() const
The same split over the quantity the loop converges on: the Phi residual, as a length.
Definition Optimize3d.cpp:2637
bool collapse_edge_after(const Tuple &t) override
The coarsening bar, the sizing restore and the rest re-stamp, after the base accepted.
Definition Optimize3d.cpp:862
std::map< int64_t, int > m_tag_bit
Definition TopoOffsetTetMesh.h:280
bool split_tet_before(const Tuple &t) override
User specified preparations and desideratas for a tet split before changing the connectivity.
Definition EdgeSplittingTet.cpp:506
int stencil_order() const
Samples per offset face; see offset_face_samples().
Definition TopoOffsetTetMesh.h:1471
std::vector< std::array< size_t, 3 > > offset_surface_faces() const
Every live offset-surface face as a sorted vertex triple.
Definition Optimize3d.cpp:3977
bool edge_split_sphere_trace(const Vector3d &p_in, const Vector3d &p_out, Vector3d &p_new, size_t &steps) const
Construction placement under sphere_trace_initialization: sphere tracing along the edge from p_in (th...
Definition EdgeSplittingTet.cpp:204
bool phase_places_front() const
Definition TopoOffsetTetMesh.h:329
std::array< size_t, 3 > face_vids(const Tuple &f) const
The three corner ids of a face tuple.
Definition Optimize3d.cpp:908
void optimize_offset(const std::filesystem::path &output_file)
The 3D optimization phase: split / collapse / swap / smooth on the shared driver.
Definition Optimize3d.cpp:4874
bool vertex_is_on_region(const size_t vid) const
Definition TopoOffsetTetMesh.h:1102
bool cell_is_released_band(size_t tid) const
Definition Optimize3d.cpp:539
bool ops_guard_refuses_collapse(size_t v1, size_t v2) const
Definition Optimize3d.cpp:926
double tet_flatness(size_t tid) const
Scale-invariant flatness: 6 * volume / longest_edge^3.
Definition Optimize3d.cpp:2418
void log_stuck_refine_census(double max_metric, double filter_energy)
Definition Optimize3d.cpp:2087
std::shared_ptr< polysolve::nonlinear::Problem > rest_energy_for_vertex(size_t vid) const
Definition Optimize3d.cpp:665
std::shared_ptr< SampleEnvelope > m_released_envelope
Definition TopoOffsetTetMesh.h:1412
bool split_before_cells(const Tuple &edge, const std::vector< Tuple > &parents) override
Split policy that is the offset's own: which region tag the two child tets inherit,...
Definition EdgeSplittingTet.cpp:607
bool vertex_is_on_surface(const size_t vid) const override
Is a vertex part of the substructure.
Definition Optimize3d.cpp:143
std::atomic< long long > m_offset_face_lookup_misses
Faces that vertex_has_live_offset_face() / offset_surface_faces_live_at() asked for and the connectiv...
Definition TopoOffsetTetMesh.h:630
double front_vertex_normal_gradient(size_t vid) const
Definition Optimize3d.cpp:1409
bool empty_input_complex()
check if the input complex is empty. Only valid after calling init_from_image(...).
Definition TopoOffsetTetMesh.cpp:703
double ring_max_quality(size_t vid) const
Definition Optimize3d.cpp:2409
void needle_scan(const char *when) const
Population scan at a named moment. Reports the count and the worst few.
Definition Optimize3d.cpp:2360
double m_front_gradient_reference
Definition TopoOffsetTetMesh.h:399
bool split_face_after(const Tuple &t) override
Compute the attributes for the added simplices.
Definition EdgeSplittingTet.cpp:417
double face_criterion_rel(const Tuple &f) const
Definition Optimize3d.cpp:3712
bool swap_after_cells(const std::vector< size_t > &tids, bool is_surface_flip) override
Propagate application data to the cells made by a successful topological swap.
Definition Optimize3d.cpp:812
std::vector< int64_t > m_phi_face_region
per m_phi_F row: region index, -1 unknown
Definition TopoOffsetTetMesh.h:220
void log_region_face_mask_health(const std::string &when) const
Definition Optimize3d.cpp:1691
std::vector< std::array< double, 8 > > optimization_metrics
Definition TopoOffsetTetMesh.h:663
bool split_edge_is_due(const Tuple &e) const
Definition EdgeSplittingTet.cpp:58
double cell_quality_rel(const size_t tid) const
AMIPS of a cell over stop_energy – the 3D twin of TriOptimizerMesh::quality_rel().
Definition Optimize3d.cpp:3696
size_t m_marching_root_splits
Definition TopoOffsetTetMesh.h:832
size_t m_debug_seq
Monotonic frame counter for the debug timeline.
Definition TopoOffsetTetMesh.h:673
size_t refine_sizing_around_worst(double max_metric) override
TetWild's stall-driven sizing refinement, verbatim; Phase A only. See the 2D twin.
Definition Optimize3d.cpp:3727
void check_offset_within_support(const char *when) const
Definition Optimize3d.cpp:3602
bool split_adjust_position(size_t v_new, const std::vector< Tuple > &children) override
Definition Optimize3d.cpp:1262
std::atomic< long long > flip_trace_n
accepted offset-surface flips
Definition TopoOffsetTetMesh.h:726
OptPhase
Which mode the hooks are running in. The 3D copy of TopoOffsetTriMesh::OptPhase.
Definition TopoOffsetTetMesh.h:325
bool face_is_offset_surface_live(const Tuple &f) const
The band's outer surface, recomputed live rather than read from the cached class.
Definition Optimize3d.cpp:3923
void optimize_offset_single_phase()
TetWild's loop, the front placed inside its smoothing passes.
Definition Optimize3d.cpp:4459
wmtk::threading::enumerable_thread_specific< CellTag > m_swap_tag
The tag swap_after_cells writes onto the tets an INTERIOR swap created, chosen in before.
Definition TopoOffsetTetMesh.h:2116
int m_ab_round
Definition TopoOffsetTetMesh.h:671
void init_surfaces_and_boundaries()
Classify every region boundary, build the per-tag containment envelopes, and tag the domain wall – on...
Definition TopoOffsetTetMesh.cpp:198
Vector3d front_vertex_normal(size_t vid) const
The field's unit direction at front vertex vid (zero where grad Phi vanishes).
Definition FrontSmooth3d.cpp:391
double cell_quality(const size_t tid) const override
The quality of cell tid, and how to write it.
Definition TopoOffsetTetMesh.h:470
void classify_sheet_faces()
Mark the mesh faces that lie on the input's envelope surface group (FaceExtra::on_sheet).
Definition TopoOffsetTetMesh.cpp:421
std::atomic< long long > funnel_case_inverted
Definition TopoOffsetTetMesh.h:764
void report_needle(const char *op, size_t tid, double parent_q) const
Where the first needles come from – a tripwire, capped at kNeedleReports.
Definition Optimize3d.cpp:2306
int m_n_regions
One field per connected piece of the input complex, and which one each band vertex is placed on....
Definition TopoOffsetTetMesh.h:212
std::atomic< long long > m_offset_face_invalid_tuple
Definition TopoOffsetTetMesh.h:634
optimization::NewtonCounters m_newton_front
Definition TopoOffsetTetMesh.h:985
bool m_plastic_active
set in optimize_offset() when deform_others
Definition TopoOffsetTetMesh.h:1428
void write_phi_grid(const std::string &path, int n) const
Definition TopoOffsetTetMesh.cpp:2071
bool smooth_after(const Tuple &t) override
User specified modifications and desideratas for after smoothing a vertex.
Definition Optimize3d.cpp:1306
std::vector< int64_t > m_phi_point_region
per m_phi_P entry: region index, -1 unknown
Definition TopoOffsetTetMesh.h:221
void check_no_vertex_on_both_surfaces(const char *when) const
Definition Optimize3d.cpp:4183
double m_gradient_reference
See offset_gradient_tolerance(). Nothing sets it on the single-phase path; it stays 0.
Definition TopoOffsetTetMesh.h:690
Per-vertex data the shared 3D optimizer knows nothing about.
Definition TopoOffsetTetMesh.h:54
uint32_t m_born_epoch
Definition TopoOffsetTetMesh.h:80
uint64_t m_boundary_mask
Which tag boundaries this vertex lies on – one bit per input tag, ambient included....
Definition TopoOffsetTetMesh.h:74
Vector3d m_turn_start
Definition TopoOffsetTetMesh.h:63
Definition Simplex.hpp:46
Definition enumerable_thread_specific.hpp:26
What the offset needs on top of the parameters every wmtk optimizer shares.
Definition Parameters.h:24
double front_conv_frac() const
Definition Parameters.h:81
bool deform_others
Definition Parameters.h:114
The "energy_gradient" criterion: the front's Newton-step ratios and the refinable faces....
Definition TopoOffsetTetMesh.h:1652
bool ring_exit
front_measure "vertex_ring"
Definition TopoOffsetTetMesh.h:1726
std::vector< size_t > refinable_vertices
Definition TopoOffsetTetMesh.h:1734
double max_ring_at_floor
the worst of them, as a ratio to the bar
Definition TopoOffsetTetMesh.h:1738
std::string sizing_floor_fact() const
Definition Optimize3d.cpp:3002
double floor_scalar
The floor, max(min_sizing_scalar, min_edge_length / l), and which of the two it is.
Definition TopoOffsetTetMesh.h:1689
double sum_ring
ratios to the bar (1 = bar)
Definition TopoOffsetTetMesh.h:1728
bool vertices_ok() const
Definition TopoOffsetTetMesh.h:1746
double avg_vertex() const
Means over the measurable front vertices / offset faces; 0 when there are none.
Definition TopoOffsetTetMesh.h:1785
double max_face_corners_at_floor
the worst of them, as a ratio to the bar
Definition TopoOffsetTetMesh.h:1686
double max_face_at_floor
the worst of them, as a ratio to the bar
Definition TopoOffsetTetMesh.h:1678
bool converged() const
Definition TopoOffsetTetMesh.h:1773
A quantity sampled at points INSIDE an offset-surface face.
Definition TopoOffsetTetMesh.h:1538
A face's shared surface tags together with the offset's own label.
Definition TopoOffsetTetMesh.h:511
The convergence criterion's own split: ||grad (Phi - c)^2|| at band vertices plus the face-interior c...
Definition TopoOffsetTetMesh.h:1633
What smoothing did with each class of vertex, per pass. Same fields as 2D.
Definition TopoOffsetTetMesh.h:938
std::atomic< int > before_bbox
base smooth_before said no: on the bounding box
Definition TopoOffsetTetMesh.h:940
std::atomic< int > before_unrounded
base smooth_before said no: could not round
Definition TopoOffsetTetMesh.h:941
std::atomic< int > interior_attempted
reached it without one
Definition TopoOffsetTetMesh.h:948
std::atomic< long long > res_before_nano
Definition TopoOffsetTetMesh.h:952
std::atomic< int > attempted
smooth_before() entered
Definition TopoOffsetTetMesh.h:939
std::atomic< int > before_phase_b_not_offset
Phase B: on an input surface, neither placed nor relaxed.
Definition TopoOffsetTetMesh.h:942
std::atomic< int > before_phase_b_enveloped_background
Phase B: envelope-held.
Definition TopoOffsetTetMesh.h:944
std::atomic< int > offset_accepted
... and the smoother kept the new position
Definition TopoOffsetTetMesh.h:947
std::atomic< int > before_phase_b_enveloped_offset
Phase B: on-offset AND held.
Definition TopoOffsetTetMesh.h:945
std::atomic< int > region_attempted
Definition TopoOffsetTetMesh.h:949
std::atomic< int > offset_attempted
reached the smoother with the offset term
Definition TopoOffsetTetMesh.h:946
size_t n_front_unmeasurable
ratio not finite: left out of the max
Definition TopoOffsetTetMesh.h:1828
size_t n_front
front vertices the max was taken over
Definition TopoOffsetTetMesh.h:1827
int kind
tids.size() as swap_before_surface() saw it: 3, 4 or 5, i.e. which swap this is.
Definition TopoOffsetTetMesh.h:2158
std::array< size_t, 4 > abcd
Definition TopoOffsetTetMesh.h:2137
How the vertex solves of a smoothing pass ended: Newton iterations taken and the status polysolve sto...
Definition SmoothVertex.hpp:75