Wildmeshing Toolkit
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | Private Member Functions | Private Attributes | List of all members
wmtk::components::topological_offset::TopoOffsetTetMesh Class Reference

The offset's tet mesh, on the shared 3D optimizer. More...

#include <TopoOffsetTetMesh.h>

Inheritance diagram for wmtk::components::topological_offset::TopoOffsetTetMesh:
wmtk::TetOptimizerMesh wmtk::TetMesh wmtk::RationalPositions wmtk::components::manifold_extraction::ManExtractTetMesh

Classes

struct  DistanceSplit
 
struct  EdgeSplitCache
 
struct  EnergyCriterion
 The "energy_gradient" criterion: the front's Newton-step ratios and the refinable faces. The 3D twin of TopoOffsetTriMesh::EnergyCriterion. More...
 
struct  FaceSamples
 A quantity sampled at points INSIDE an offset-surface face. More...
 
struct  FaceSnapshot
 A face's shared surface tags together with the offset's own label. More...
 
struct  FaceSplitCache
 
struct  GradientSplit
 The convergence criterion's own split: ||grad (Phi - c)^2|| at band vertices plus the face-interior chord diagnostic and the normal-aligned reference quantity. Same fields as the 2D GradientSplit, face samples in place of edge samples. More...
 
struct  OptSplitCache
 
struct  SmoothingProgress
 
struct  SmoothTrace
 What smoothing did with each class of vertex, per pass. Same fields as 2D. More...
 
struct  SwapSurfaceSides
 
struct  TetSplitCache
 

Public Types

enum class  EdgeSplitMode { Midpoint = 0 , SphereTrace = 1 , Optimization = 5 }
 
enum class  OptPhase { A , B , Single }
 Which mode the hooks are running in. The 3D copy of TopoOffsetTriMesh::OptPhase. More...
 
enum class  EnvelopeSetup { PerTag , WallComplex }
 Which boundaries the region-class envelopes hold, and how they are built. More...
 
using VertexExtraCol = wmtk::AttributeCollection< VertexExtra >
 
using EdgeAttCol = wmtk::AttributeCollection< EdgeAttributes >
 
using FaceExtraCol = wmtk::AttributeCollection< FaceExtra >
 
using TetAttCol = wmtk::AttributeCollection< TetAttributes >
 
- Public Types inherited from wmtk::TetOptimizerMesh
using FaceAttributes = wmtk::SurfaceTagAttributes
 
using VertAttCol = AttributeCollection< VertexAttributes >
 
using FaceAttCol = AttributeCollection< FaceAttributes >
 
using SurfaceTopoSignature = wmtk::utils::SurfaceTopoSignature
 
- Public Types inherited from wmtk::TetMesh
enum class  OpKind : int {
  split , collapse , swap_32 , swap_44 ,
  swap_56 , swap_face , COUNT
}
 
enum class  OpEvent : int {
  attempt , before_hook , link_condition , no_return_tet ,
  duplicate_tet , topology , valence , boundary ,
  exists , no_case_allowed , no_better_case , out_of_slots ,
  after_hook , invariants , committed , COUNT
}
 
template<typename T >
using vector = std::vector< T >
 
using VertexMutex = wmtk::threading::VertexMutex
 

Public Member Functions

void classify_sheet_faces ()
 Mark the mesh faces that lie on the input's envelope surface group (FaceExtra::on_sheet).
 
void init_region_potentials (double delta, double effective_factor)
 
void assign_band_regions (bool log=true)
 
void log_front_profile (size_t vid)
 Diagnostic: the front objective of one vertex along its normal, offset term vs total.
 
int vertex_region (const size_t vid) const
 
int edge_region (const size_t va, const size_t vb) const
 
const OffsetPotential3D & potential_for_region (const int region) const
 
const OffsetPotential3D & potential_for (const size_t vid) const
 
std::shared_ptr< const OffsetPotential3D > potential_ptr_for (const size_t vid) const
 
const OffsetPotential3D & potential_for_edge (const size_t va, const size_t vb) const
 
const OffsetPotential3D & potential_for_face (const Tuple &f) const
 The field of the band cell a live offset face belongs to.
 
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 intersection of everything that holds it, or null if nothing does.
 
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. Alternating projection onto the worst-violated real member; never asks a composite (see TagEnvelopes.hpp).
 
bool phase_places_front () const
 
EnvelopeSetup envelope_setup () const
 
std::string envelope_key_name (int64_t tag) const
 The name a tag or pseudo-tag prints under.
 
bool face_is_complex_boundary (const Tuple &f) const
 
void build_boundary_envelopes (const char *when, EnvelopeSetup setup)
 
void rebuild_offset_envelope ()
 
void check_no_vertex_on_both_surfaces (const char *when) const
 
void optimize_offset_single_phase ()
 TetWild's loop, the front placed inside its smoothing passes.
 
double phase_b_front_gradient_linf ()
 
 TopoOffsetTetMesh (Parameters &_m_offset_params, int _num_threads=0)
 
double cell_quality (const size_t tid) const override
 The quality of cell tid, and how to write it.
 
void set_cell_quality (const size_t tid, const double q) override
 
void set_vertex_position (const size_t vid, const Vector3d &p)
 Place a vertex, keeping its exact and rounded coordinates in step.
 
bool face_is_offset (const size_t fid) const
 
bool face_is_region (const size_t fid) const
 
FaceSnapshot face_snapshot (const size_t fid) const
 
void restore_face (const size_t fid, const FaceSnapshot &s)
 
void label_offset_boundary ()
 Tag the two tracked surfaces for the optimization phase.
 
bool cell_in_region (const size_t tid) const
 
bool cell_is_input_complex (const size_t tid) const
 Whether tet tid is part of the INPUT complex the band wraps.
 
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).
 
void optimize_offset (const std::filesystem::path &output_file)
 The 3D optimization phase: split / collapse / swap / smooth on the shared driver.
 
std::pair< double, double > compute_distance_deviation () const
 How far the offset surface is from where it should be: {max, avg} over vertices.
 
void log_worst_dist_vertex () const
 
bool face_is_offset_surface_live (const Tuple &f) const
 The band's outer surface, recomputed live rather than read from the cached class.
 
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.
 
std::vector< std::array< size_t, 2 > > offset_surface_edges () const
 
std::vector< std::array< size_t, 3 > > offset_surface_faces () const
 Every live offset-surface face as a sorted vertex triple.
 
std::vector< Tuple > offset_surface_faces_live_at (size_t vid) const
 The live offset-surface faces incident to vid.
 
bool vertex_has_live_offset_face (size_t vid) const
 
void refresh_offset_membership (size_t vid)
 Re-derive m_is_on_offset for one vertex from the cell labels, exactly.
 
std::pair< size_t, size_t > offset_membership_mismatches () const
 
void check_offset_membership (const char *when) const
 
void report_offset_face_lookup_misses (const char *when) const
 
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? Debug-frame diagnostic; see write_vtu(). Costs one pass over the live offset faces, no field evaluation.
 
void write_debug_pvd () const
 
void flip_trace_record (double before, double after)
 
std::string flip_funnel_report () const
 
void flip_funnel_reset ()
 
void op_event (OpKind k, OpEvent e) const override
 
bool split_edge_is_due (const Tuple &e) const
 
bool marching_split_edge_before (const Tuple &t)
 
bool marching_split_edge_after (const Tuple &t)
 
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 (the endpoint in the input complex, label != 0) towards p_out (the background endpoint) for the point where d(x) = target_distance, d(x) the distance to the input complex through m_input_complex_bvh. From t = 0 the trace evaluates d at the current point and steps forward by target_distance - d, the largest step that cannot cross the level set (d is 1-Lipschitz); it stops when |d - target_distance| <= sphere_trace_target_rel_tol x target_distance and returns true with p_new there. It returns false, p_new untouched, as soon as the current point reaches or passes p_out (t >= L: the level set is not on the edge) or would move behind p_in (d(p_in) already beyond the target); the caller then places the plain midpoint. Every step taken is longer than the tolerance, so the trace ends within L / (tol x target_distance) steps; steps returns how many it took. No snapping away from the endpoints: a point found arbitrarily close to p_out is used as is.
 
bool collapse_edge_before (const Tuple &t) override
 Reject any collapse that violates the substructure link condition, and remember the survivor's sizing for sizing_collapse_min = false.
 
bool collapse_edge_after (const Tuple &t) override
 The coarsening bar, the sizing restore and the rest re-stamp, after the base accepted.
 
bool collapse_before_vertex (size_t v1, size_t v2, double edge_length) override
 
bool collapse_after_connectivity (size_t v1, size_t v2, const std::vector< std::array< size_t, 2 > > &boundary_edges) override
 
bool collapse_is_order_2_edge (const std::array< size_t, 2 > &e) override
 
void collapse_after_vertex (size_t v1, size_t v2) override
 
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 (class match, mask match). The geometric half is the shared swap's containment check. See Optimize3d.cpp.
 
bool swap_before_surface (const std::vector< size_t > &tids, size_t a, size_t b, size_t c, size_t d) override
 
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.
 
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, and which of the two tracked surfaces the new vertex joined. See EdgeSplittingTet.cpp.
 
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.
 
bool split_adjust_position (size_t v_new, const std::vector< Tuple > &children) override
 
void split_after_vertex (size_t v_new, bool is_edge_open_boundary) override
 Application metadata not represented by the shared vertex attributes.
 
bool is_open_boundary_edge (const Tuple &e) override
 
bool smooth_before (const Tuple &t) override
 User specified preparations and desideratas for smoothing a vertex.
 
bool smooth_after (const Tuple &t) override
 User specified modifications and desideratas for after smoothing a vertex.
 
bool vertex_is_on_domain_boundary (const size_t vid) const
 Identification only – no operation refuses the domain wall through these.
 
bool face_is_on_domain_boundary (const size_t fid) const
 
void init_surfaces_and_boundaries ()
 Classify every region boundary, build the per-tag containment envelopes, and tag the domain wall – once, from the input mesh, before offset construction runs.
 
bool is_edge_on_region (const Tuple &loc)
 
bool is_edge_on_offset (const Tuple &loc)
 
void mark_input_complex_vertices ()
 
void warn_if_offset_reaches_domain_boundary () const
 Warn if the offset band has grown into the domain boundary.
 
void log_smoothing_pass_accounting () override
 
double ring_max_quality (size_t vid) const
 
double tet_amips (const size_t tid) const
 AMIPS of one tet, the cube root of cell_quality(); the number every log line reports.
 
double tet_flatness (size_t tid) const
 Scale-invariant flatness: 6 * volume / longest_edge^3.
 
void needle_forensics () const
 The full post-mortem on why nothing removes the flat cells; see the 2D twin.
 
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}.
 
double face_resolution_or_inf (size_t a, size_t b, size_t c) const
 
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
 
double vertex_ring_measure (const std::vector< std::array< size_t, 3 > > &ring) const
 
double ring_face_area (size_t a, size_t b, size_t c) const
 
bool ops_guard_refuses_collapse (size_t v1, size_t v2) const
 
std::array< size_t, 3 > face_vids (const Tuple &f) const
 The three corner ids of a face tuple.
 
void log_smooth_trace () const
 
void log_region_face_mask_health (const std::string &when) const
 
void audit_surface_containment (const std::string &when) const
 
bool vertex_is_on_region (const size_t vid) const
 
uint64_t tag_bits (const CellTag &tags) const
 The three helpers of the per-tag envelope dispatch.
 
uint64_t vertex_boundary_mask (const size_t vid) const
 
uint64_t face_mask (const std::array< size_t, 3 > &vids) const
 
uint64_t face_boundary_bits (const Tuple &f) const
 
std::shared_ptr< SampleEnvelope > envelope_for_mask (uint64_t mask) const
 
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 containment requirement; the offset surface does not, except in Phase A where m_offset_envelope holds it where the last smoothing pass left it.
 
bool allow_surface_swap () const override
 
bool swap_quality_allowed (const double after, const double before, const bool is_surface_flip) const override
 
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]. The energy returned is the base's.
 
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.
 
bool check_surface_topology () const override
 
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.
 
std::shared_ptr< SampleEnvelope > smoothing_containment_envelope (const size_t vid) const override
 
bool smooth_front_vertex_phase_b (const Tuple &t)
 Phase B placement of a front vertex: the shared smoother with the offset's options, or the 1-D solve along the vertex's move direction under front_normal_projection. See FrontSmooth3d.cpp.
 
double front_vertex_normal_gradient (size_t vid) const
 
Vector3d front_vertex_move_direction (size_t vid) const
 
double front_move_alignment (size_t vid) const
 
bool front_vertex_alignment_traps_1d_solve (size_t vid) const
 
double front_vertex_conv_ratio (size_t vid) const
 
bool front_vertex_placed (size_t vid) const
 THE definition of "placed" for a vertex on the offset surface.
 
bool front_placed_by_ratio (const double ratio) const
 
double edge_conv_ratio (size_t a, size_t b) const
 
double face_conv_ratio (size_t a, size_t b, size_t c) const
 
Vector3d front_vertex_normal (size_t vid) const
 The field's unit direction at front vertex vid (zero where grad Phi vanishes).
 
std::shared_ptr< polysolve::nonlinear::Problem > phase_b_front_objective (size_t vid, const Vector3d &x) const
 
std::shared_ptr< polysolve::nonlinear::Problem > smoothing_extra_energy (const size_t vid) const override
 
std::shared_ptr< SampleEnvelope > released_envelope () const
 
bool face_borders_released_boundary (const Tuple &f) const
 
bool cell_is_deformable (size_t tid) const
 Under deform_others the same set as cell_is_plastic(): every cell outside the band.
 
bool cell_is_plastic (size_t tid) const
 
void stamp_plastic_rests ()
 Stamp rest := current for every plastic cell; called before every operation group.
 
bool smooth_plastic_vertex (const Tuple &t)
 The plastic vertex's smoothing: rest-shape AMIPS over its ring, nothing else.
 
bool cell_is_released_band (size_t tid) const
 
void stamp_rest_cell (size_t tid)
 
void release_deformable_regions ()
 
std::shared_ptr< polysolve::nonlinear::Problem > rest_energy_for_vertex (size_t vid) const
 
std::shared_ptr< polysolve::nonlinear::Problem > phase_b_front_energy (size_t vid, const std::shared_ptr< const OffsetPotential3D > &pot) const
 
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 over its own target) in Phase B. See the 2D twin.
 
double optimization_stop_metric () const override
 stop_energy outside Phase B, 1.0 in it – in the same units as the line above.
 
int stencil_order () const
 Samples per offset face; see offset_face_samples().
 
int stencil_points_per_face () const
 
double offset_residual_tolerance () const
 
double offset_gradient_tolerance () const
 
double gradient_reference () const
 The scale offset_gradient_tolerance() is a fraction of; 0 on the single-phase path.
 
void check_offset_within_support (const char *when) const
 
DistanceSplit distance_deviation_split () const
 
DistanceSplit residual_split () const
 The same split over the quantity the loop converges on: the Phi residual, as a length.
 
std::vector< bool > band_vertex_mask () const
 Which vertices lie on the band's outer surface. Shared by every measurement.
 
double max_band_vertex_distance () const
 
double band_vertex_distance_error (const size_t vid) const
 |dist(vid, input complex) - target_distance|. Diagnostic: the Euclidean offset.
 
double band_vertex_residual (const size_t vid) const
 How far vid is from the level set Phi = c, as a length.
 
template<typename Visit >
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, wa, wb, wc) with the barycentric weights that built it: every (i, j, l) with i + j + l = k + 2 and each >= 1, so k = 1 is the centroid alone and the counts are 1, 3, 6, 10 for k = 1..4. Strictly interior – no sample ever lands on an edge or a corner, where the interpolant is exact by construction and the sag is identically zero.
 
template<typename Visit >
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.
 
FaceSamples offset_face_samples (const Tuple &f) const
 
GradientSplit gradient_split (bool include_face_samples=true) const
 
EnergyCriterion energy_criterion ()
 
double front_chord_target (size_t va, size_t vb, double len, double sag, double tube) const
 
size_t refine_front_by_halving (const std::vector< EnergyCriterion::Refinable > &faces)
 
size_t refine_front_by_halving (const std::vector< size_t > &vertices)
 
void grade_sizing (double grade, const std::vector< size_t > &seeds)
 
size_t grade_sizing_by_distance (const std::vector< size_t > &seeds)
 
SmoothingProgress smoothing_progress (const std::vector< Vector3d > &before)
 Measure a pass: before holds every live vertex's position before it, indexed by vid.
 
void smooth_group_to_convergence (const char *group_name)
 
double edge_interpolation_residual (size_t a, size_t b) const
 The interpolation residual of front edge (a, b), see EnergyCriterion. -1 unmeasurable.
 
Vector3d offset_vertex_normal (const size_t vid) const
 
void report_outside_support (const char *when, const DistanceSplit &s) const
 Turn a residual_split()'s outside-support tally into the hard error.
 
bool band_vertex_is_reachable (const size_t vid) const
 
size_t refine_sizing_around_worst (double max_metric) override
 TetWild's stall-driven sizing refinement, verbatim; Phase A only. See the 2D twin.
 
void log_stuck_refine_census (double max_metric, double filter_energy)
 
void log_refine_block_census (const std::string &when, double filter_energy) const
 
bool collapse_quality_allowed (size_t v1, double q, double ring_max) const override
 Instrumentation only: which operation manufactures the MAX_ENERGY needles.
 
void report_needle (const char *op, size_t tid, double parent_q) const
 Where the first needles come from – a tripwire, capped at kNeedleReports.
 
void needle_scan (const char *when) const
 Population scan at a named moment. Reports the count and the worst few.
 
bool optimization_bare_coarsen_passes () const override
 
double face_criterion_rel (const Tuple &f) const
 
double cell_quality_rel (const size_t tid) const
 AMIPS of a cell over stop_energy – the 3D twin of TriOptimizerMesh::quality_rel().
 
double amips_rel_at_face (const Tuple &f) const
 ... and the worst of the (up to two) cells a face separates.
 
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()), labelled "r<round><phase><pass>_<op>" / "r<round><phase>_end". Same scheme as 2D.
 
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.
 
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, and one "NNNNN<tab>label" line in <output>_frames.txt. Every debug frame the run writes – the input as loaded, the construction stages, and the optimization's own frames through write_optimization_debug_output() – goes through this sequence, so the numbers are consecutive and the .txt says what each one is. The only debug files outside it are the ones that are not this mesh: <output>_input_complex.vtu and the phi grid.
 
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
 
bool ambient_assert ()
 check that the ambient tag does not overlap with any other tags
 
void label_input_complex ()
 label input simplicial complex simplices, as defined in m_offset_params.offset_selection
 
bool empty_input_complex ()
 check if the input complex is empty. Only valid after calling init_from_image(...).
 
void init_input_complex_bvh ()
 Build the input complex's BVH and keep the extraction the potential needs, and number the complex's connected pieces. Must be called after init_from_image(...) and label_input_complex().
 
void init_offset_potential ()
 Build the smooth offset potential from the extraction init_input_complex_bvh() kept.
 
size_t flood_fill ()
 label connected simplicial complex components (simplices labelled 1 or 2)
 
std::vector< std::array< size_t, 3 > > get_faces_by_condition (std::function< bool(const FaceAttributes &)> cond) const
 
bool split_edge_before (const Tuple &t) override
 User specified preparations and desideratas for an edge split before changing the connectivity.
 
bool split_edge_after (const Tuple &t) override
 This function computes the attributes for the added simplices. User specified modifications and desideratas for after an edge split.
 
bool split_face_before (const Tuple &t) override
 User specified preparations and desideratas for a face split before changing the connectivity.
 
bool split_face_after (const Tuple &t) override
 Compute the attributes for the added simplices.
 
bool split_tet_before (const Tuple &t) override
 User specified preparations and desideratas for a tet split before changing the connectivity.
 
bool split_tet_after (const Tuple &t) override
 Compute the attributes for the added simplices.
 
bool invariants (const std::vector< Tuple > &tets) override
 
void execute_offset (const std::filesystem::path &output_file)
 
void marching_tets ()
 
bool is_simplicially_embedded () const
 
bool tet_is_simp_emb (const Tuple &t) const
 
void simplicial_embedding ()
 
void set_offset_tet_tags ()
 update 'tags' data for tets in the offset region (tets labelled 2)
 
bool offset_is_manifold ()
 verify that the closed offset region (simplices labelled 1 or 2) form a manifold region.
 
void write_phi_grid (const std::string &path, int n) const
 
void write_input_complex (const std::string &path)
 
void write_vtu (const std::string &path)
 
void write_msh_groups (const std::string &file)
 
bool is_order_2_edge (const Tuple &e) const
 
bool is_order_2_edge (const std::array< size_t, 2 > &e) const
 
bool vertex_is_on_surface (const size_t vid) const override
 Is a vertex part of the substructure.
 
bool face_is_on_surface (const size_t fid) const override
 Is a face part of the substructure.
 
size_t get_order_of_vertex (const size_t vid) const override
 Get the order of a vertex.
 
void init_vertex_order ()
 Compute the vertex order for every vertex.
 
void compute_vertex_partition ()
 assign each vertex a partition id (by spatial Morton order). A no-op if NUM_THREADS == 0.
 
size_t get_partition_id (const Tuple &loc) const
 
std::vector< size_t > connected_components_helper (const size_t &v_id)
 all one-ring vertices through input simplices (labelled 1 or 2)
 
void reset_connected_components ()
 reset connected component assignments.
 
- Public Member Functions inherited from wmtk::TetOptimizerMesh
bool is_force_split_edge (const size_t v1, const size_t v2) const
 
 TetOptimizerMesh (OptimizerParameters &params, std::shared_ptr< SampleEnvelope > env)
 
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.
 
void compute_vertex_partition ()
 
void compute_vertex_partition_morton ()
 
size_t get_partition_id (const Tuple &loc) const
 
double get_length2 (const Tuple &l) const
 
bool is_inverted (const std::array< size_t, 4 > &vs) const
 
bool is_inverted (const Tuple &loc) const
 
bool is_inverted_f (const Tuple &loc) const
 Inversion check using only the double positions.
 
double get_quality (const std::array< size_t, 4 > &vs) const
 
double get_quality (const Tuple &loc) const
 
std::tuple< double, double > get_max_avg_energy ()
 
virtual void update_attributes ()
 Update the attributes of the mesh after an iteration of operations.
 
void mesh_improvement (int max_its=80)
 
std::tuple< double, double > local_operations (const std::array< int, 4 > &ops, bool collapse_limit_length=true)
 
bool round (const Tuple &v)
 Round a vertex position to floating point, if that inverts no incident tet.
 
bool is_edge_on_surface (const Tuple &loc)
 
bool is_edge_on_bbox (const Tuple &loc)
 
int edge_incident_surface_face_count (const Tuple &e)
 How many of the faces incident to edge e are on the tracked surface.
 
bool surface_triangle_is_outside (const size_t a, const size_t b, const size_t c) const
 
std::vector< std::array< size_t, 3 > > get_faces_by_condition (std::function< bool(const FaceAttributes &)> cond) const
 
void output_faces (std::string file, std::function< bool(const FaceAttributes &)> cond)
 
void gradation_smooth_sizing (double grade, const std::vector< size_t > &seeds)
 Grade the refined sizing region into its surroundings (monotone, only lowers).
 
double active_quality_threshold () const
 Cell-quality threshold above which a tet is "active" (worth operating on) for the skip-good-regions filter.
 
virtual std::vector< size_t > active_vertices () const
 
void split_all_edges ()
 
void collapse_all_edges (bool is_limit_length=true)
 
size_t coarsen_mesh ()
 Coarsen the mesh without letting the max energy rise.
 
bool coarsen_collapse_edge (const Tuple &e, std::vector< Tuple > &new_tets)
 One collapse under the coarsening rules, outside a coarsening pass.
 
size_t swap_all_edges_32 ()
 
bool swap_edge_before (const Tuple &t) override
 User specified preparations and desideratas for an 3-2 edge swap before changing the conenctivity.
 
bool swap_edge_after (const Tuple &t) override
 User specified modifications and desideratas for after a 3-2 edge swap.
 
size_t swap_all_edges_44 ()
 
bool swap_edge_44_before (const Tuple &t) override
 User specified preparations and desideratas for an 4-4 edge swap before changing the connectivity.
 
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.
 
bool swap_edge_44_after (const Tuple &t) override
 User specified modifications and desideratas for after a 4-4 edge swap.
 
size_t swap_all_edges_56 ()
 
bool swap_edge_56_before (const Tuple &t) override
 User specified preparations and desideratas for a 5-6 edge swap before changing the connectivity.
 
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.
 
bool swap_edge_56_after (const Tuple &t) override
 User specified modifications and desideratas for after a 5-6 edge swap.
 
size_t swap_all_faces ()
 
bool swap_face_before (const Tuple &t) override
 User specified preparations and desideratas for an 2-3 face swap befroe changing the geometry.
 
bool swap_face_after (const Tuple &t) override
 User specified modifications and desideratas for after a 2-3 face swap.
 
size_t swap_all_edges_all ()
 
bool prepare_surface_flip (const Tuple &t, const std::vector< size_t > &incident_tets)
 
SurfaceTopoSignature surface_topology_signature () const
 
void warn_if_surface_topology_changed (const SurfaceTopoSignature &before, const char *where) const
 
void smooth_all_vertices (const size_t n_iters=1)
 
- Public Member Functions inherited from wmtk::TetMesh
size_t vert_capacity () const
 get the current largest global vid
 
size_t tet_capacity () const
 get the current largest global tid
 
size_t vertex_size () const
 get the number of unremoved verticies
 
size_t tet_size () const
 get the number of unremoved tets
 
void init (size_t n_vertices, const std::vector< std::array< size_t, 4 > > &tets)
 
void init_with_isolated_vertices (size_t n_vertices, const std::vector< std::array< size_t, 4 > > &tets)
 
void init (const MatrixXi &T)
 Generate the connectivity of the mesh from an IGL-style T matrix.
 
bool split_edge (const Tuple &t, std::vector< Tuple > &new_tets)
 
virtual bool collapse_edge (const Tuple &t, std::vector< Tuple > &new_tets)
 
bool link_condition (const Tuple &t)
 
bool collapse_edge_conn (const Tuple &loc0, size_t &v1_id, Tuple &new_loc, std::map< size_t, wmtk::TetMesh::VertexConnectivity > &rollback_vert_conn, std::vector< size_t > &n1_t_ids_copy, std::vector< size_t > &new_tet_id, std::vector< TetrahedronConnectivity > &old_tets)
 
bool collapse_edge_check_topology (const std::vector< size_t > &new_tet_id)
 Check topology after collapse connectivity change. This is a sanity check and should not be necessary.
 
void collapse_edge_rollback (size_t &v1_id, std::map< size_t, wmtk::TetMesh::VertexConnectivity > &rollback_vert_conn, std::vector< size_t > &n1_t_ids, std::vector< size_t > &new_tet_id, std::vector< TetrahedronConnectivity > &old_tets)
 
bool swap_edge_56 (const Tuple &t, std::vector< Tuple > &new_tets)
 
bool swap_edge_44 (const Tuple &t, std::vector< Tuple > &new_tets)
 
bool swap_edge (const Tuple &t, std::vector< Tuple > &new_tets)
 3-2 edge swap
 
bool swap_face (const Tuple &t, std::vector< Tuple > &new_tets)
 2-3 face swap
 
bool smooth_vertex (const Tuple &t)
 
bool split_tet (const Tuple &t, std::vector< Tuple > &new_tets)
 Split a tet in 4 tets.
 
bool split_face (const Tuple &t, std::vector< Tuple > &new_tets)
 Split a face in 3 faces.
 
void triangle_insertion (const std::vector< Tuple > &intersected_tets, const std::vector< Tuple > &intersected_edges, std::vector< size_t > &new_edge_vids, std::vector< size_t > &new_center_vids, std::vector< std::array< size_t, 4 > > &center_split_tets)
 Insert a triangle into a tetmesh, with known intersection information.
 
bool insert_point (const Tuple &t, std::vector< Tuple > &new_tets)
 Insert a point into a tetmesh inside a tet. In general position, this split a tet into 4. In face position, split two tets. In edge position, In point position, do nothing.
 
virtual bool insert_point_before (const Tuple &t)
 
virtual bool insert_point_after (std::vector< Tuple > &new_tets)
 
void consolidate_mesh ()
 cleans up the deleted vertices or tetrahedra, fixes the corresponding indices, and reset the version number. WARNING: it invalidates all tuples!
 
std::vector< Tuple > get_edges () const
 
std::vector< Tuple > get_faces () const
 
std::vector< Tuple > get_vertices () const
 
std::vector< Tuple > get_tets () const
 
virtual void for_each_face (const std::function< void(const TetMesh::Tuple &)> &)
 looping through all the unique edges and perform the given function
 
void set_preallocation_factor (double factor)
 Preallocation factor: init/consolidate reserve capacity = max(floor, ceil(factor * live_count)) so operations can grab fresh slots without resizing the storage. When a pass exhausts the reserved capacity the affected operations fail (and are retried later after a consolidate). Tune per application (e.g. from JSON); values < 1 are clamped to 1.
 
double preallocation_factor () const
 
bool slots_exhausted () const
 
void clear_slots_exhausted ()
 
size_t request_tet_slots (size_t n)
 
size_t request_vert_slots (size_t n)
 
void ensure_free_tet_capacity (size_t extra)
 
void ensure_free_vert_capacity (size_t extra)
 
bool op_refused (const OpKind k, const OpEvent e) const
 op_event() for a refusal, returning false so a site reads return op_refused(...).
 
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).
 
Tuple tuple_from_edge (const std::array< size_t, 2 > &vids) const
 get a Tuple from global vids of the 2 end of an edge
 
Tuple tuple_from_face (size_t tid, int local_fid) const
 get a Tuple from global tetra index and local face index (from 0-3).
 
std::tuple< Tuple, size_t > tuple_from_face (const std::array< size_t, 3 > &vids) const
 get a Tuple and the global face index from global vertex index of the face.
 
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.
 
size_t lowest_common_tet (size_t v0_id, size_t v1_id, size_t v2_id) const
 Lowest tet id incident to all three vertices, or size_t(-1) if there is none.
 
size_t vertex_valence (const size_t vid) const
 Number of tets incident to a vertex, in O(1).
 
std::tuple< Tuple, size_t > tuple_from_face (const simplex::Face &f) const
 
Tuple tuple_from_vertex (size_t vid) const
 get a Tuple from global vertex index
 
Tuple tuple_from_tet (size_t tid) const
 get a Tuple from global tetra index
 
Tuple tuple_from_vids (size_t vid0, size_t vid1, size_t vid2, size_t vid3) const
 Get a Tuple from global vertex IDs.
 
simplex::Tet simplex_from_tet (const Tuple &t) const
 
simplex::Tet simplex_from_tet (const size_t tid) const
 
simplex::Face simplex_from_face (const Tuple &t) const
 
simplex::Edge simplex_from_edge (const Tuple &t) const
 
Tuple switch_vertex (const Tuple &t) const
 wrapper function from Tuple::switch_vertex
 
Tuple switch_edge (const Tuple &t) const
 wrapper function from Tuple::switch_edge
 
Tuple switch_face (const Tuple &t) const
 wrapper function from Tuple::switch_face
 
std::optional< Tuple > switch_tetrahedron (const Tuple &t) const
 wrapper function from Tuple::switch_tetrahedron
 
std::vector< Tuple > get_one_ring_tets_for_vertex (const Tuple &t) const
 Get the one ring tets for a vertex.
 
const std::vector< size_t > & get_one_ring_tids_for_vertex (const Tuple &t) const
 Get the one ring tids for vertex.
 
const std::vector< size_t > & get_one_ring_tids_for_vertex (const size_t vid) const
 
std::vector< Tuple > get_one_ring_vertices_for_vertex (const Tuple &t) const
 Get the one ring vertices for a vertex.
 
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.
 
std::vector< size_t > get_one_ring_vids_for_vertex (size_t vid) const
 Get the one ring vids for vertex.
 
std::vector< size_t > get_one_ring_vids_for_vertex_adj (size_t vid) const
 Duplicate of the function TetMesh::get_one_ring_vids_for_vertex.
 
std::vector< size_t > get_one_ring_vids_for_vertex_adj (size_t vid, std::vector< size_t > &cache)
 Duplicate of the function TetMesh::get_one_ring_vids_for_vertex.
 
std::vector< Tuple > get_incident_tets_for_edge (const Tuple &t) const
 Get the incident tets for edge.
 
std::vector< Tuple > get_incident_tets_for_edge (const size_t vid0, const size_t vid1) const
 
std::vector< size_t > get_incident_tids_for_edge (const Tuple &t) const
 
std::vector< size_t > get_incident_tids_for_edge (const size_t vid0, const size_t vid1) const
 
std::vector< Tuple > get_one_ring_tets_for_edge (const Tuple &t) const
 Get the one ring tets for edge.
 
std::vector< std::array< size_t, 3 > > vertex_adjacent_boundary_faces (const Tuple &t) const
 
std::array< Tuple, 4 > oriented_tet_vertices (const Tuple &t) const
 
std::array< size_t, 4 > oriented_tet_vids (const Tuple &t) const
 
std::array< size_t, 4 > oriented_tet_vids (const size_t tid) const
 
std::array< Tuple, 3 > get_face_vertices (const Tuple &t) const
 Get the 3 vertices of a face represented by Tuple.
 
std::array< size_t, 3 > get_face_vids (const Tuple &t) const
 
std::array< Tuple, 6 > tet_edges (const Tuple &t) const
 get the 6 edges of a tet represented by Tuples
 
void check_tuple_validity (const Tuple &t) const
 
bool check_mesh_connectivity_validity () const
 checks the validity of the connectivity of the mesh. Including the validity of each Tuple
 
void remove_tets_by_ids (const std::vector< size_t > &tids)
 remove the tetrahedrons in the mesh that have given tet ids
 
void start_protect_attributes ()
 
void release_protect_attributes ()
 
void rollback_protected_attributes ()
 
int release_vertex_mutex_in_stack ()
 
int release_vertex_mutex_to (size_t mark)
 Release the mutexes taken since the release stack held mark entries.
 
bool try_set_vertex_mutex_n_ring (const Tuple &v, int threadid, int n)
 Lock every vertex within graph distance n of v, the seed included.
 
bool try_set_vertex_mutex_n_ring (size_t vid, int threadid, int n)
 
bool try_set_edge_mutex_n_ring (const Tuple &e, int threadid, int n)
 try_set_vertex_mutex_n_ring seeded from both ends of an edge.
 
bool try_set_face_mutex_n_ring (size_t v1, size_t v2, size_t v3, int threadid, int n)
 try_set_vertex_mutex_n_ring seeded from the three vertices of a face.
 
void for_each_edge (const std::function< void(const TetMesh::Tuple &)> &)
 perform the given function for each edge
 
void for_each_vertex (const std::function< void(const TetMesh::Tuple &)> &)
 perform the given function for each vertex
 
void for_each_tetra (const std::function< void(const TetMesh::Tuple &)> &)
 perform the given function for each tet
 
simplex::SimplexCollection get_surface_faces_for_vertex (const size_t vid) const
 Get all faces on the surface that are incident to vid.
 
simplex::SimplexCollection get_surface_faces_for_edge (const std::array< size_t, 2 > &vids) const
 Get all faces on the surface that are incident to the edge.
 
size_t get_num_surface_faces_for_edge (const std::array< size_t, 2 > &vids) const
 Get the number of surface faces incident to the edge.
 
size_t compute_vertex_order (const size_t vid) const
 Compute the vertex order for a single vertex.
 
size_t get_order_of_edge (const std::array< size_t, 2 > &vids) const
 Compute the order of an edge.
 
bool substructure_link_condition (const Tuple &e_tuple) const
 Link condition that also considers substructures.
 
size_t tet_storage_capacity () const
 
size_t vert_storage_capacity () const
 
bool try_set_vertex_mutex_two_ring (const Tuple &v, int threadid)
 Lock v's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_vertex_mutex_two_ring_vid (const Tuple &v, int threadid)
 try_set_vertex_mutex_two_ring reached through vids rather than Tuples.
 
bool try_set_vertex_mutex_two_ring_vid (size_t v, int threadid)
 try_set_vertex_mutex_two_ring reached through vids rather than Tuples.
 
bool try_set_edge_mutex_two_ring (const Tuple &e, int threadid=0)
 Lock the edge's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_face_mutex_two_ring (const Tuple &f, int threadid=0)
 Lock the face's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_face_mutex_two_ring (const Tuple &v1, const Tuple &v2, const Tuple &v3, int threadid=0)
 Lock the face's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_face_mutex_two_ring (size_t v1, size_t v2, size_t v3, int threadid=0)
 Lock the face's one-ring and, partially, its two-ring. See the note above.
 
bool try_set_vertex_mutex_one_ring (const Tuple &v, int threadid=0)
 Lock v and its one-ring. Complete, unlike the two-ring family.
 
size_t cell_capacity () const
 
Tuple tuple_from_cell (size_t cid) const
 
- Public Member Functions inherited from wmtk::RationalPositions
size_t round_all_vertices ()
 Try to round every un-rounded vertex; returns the number reclaimed.
 
bool round_and_check_all_rounded ()
 Run the sweep, then report whether the mesh is now fully rounded.
 

Static Public Member Functions

static bool & split_off_longest ()
 

Public Attributes

std::array< size_t, 4 > m_init_counts = {{0, 0, 0, 0}}
 
size_t m_tags_count
 
int64_t m_sheet_tag = -1
 
MatrixXd m_sheet_V
 The surface group as loaded, kept because the classification below is redone on demand.
 
MatrixXi m_sheet_F
 
std::shared_ptr< SimplicialComplexBVH > m_input_complex_bvh
 The input complex as loaded. Built once, never rebuilt.
 
std::shared_ptr< OffsetPotential3D > m_offset_potential
 The smooth offset potential, and with it the definition of the offset itself.
 
std::shared_ptr< SampleEnvelope > m_input_complex_envelope
 The exact-kind envelope of the input complex, built only for offset_field "euclidean". Null otherwise.
 
int m_n_regions = 0
 One field per connected piece of the input complex, and which one each band vertex is placed on. See TopoOffsetTriMesh::m_region_potentials for the full argument.
 
std::vector< std::shared_ptr< OffsetPotential3D > > m_region_potentials
 
std::vector< std::shared_ptr< SimplicialComplexBVH > > m_region_bvhs
 
std::vector< int64_t > m_phi_vert_region
 per m_phi_V row: region index
 
std::vector< int64_t > m_phi_seg_region
 per m_phi_E row: region index, -1 unknown
 
std::vector< int64_t > m_phi_face_region
 per m_phi_F row: region index, -1 unknown
 
std::vector< int64_t > m_phi_point_region
 per m_phi_P entry: region index, -1 unknown
 
std::vector< int > m_cell_region
 per tet: band's region, -1 none, -2 reached from two
 
std::vector< int > m_vertex_region
 per vertex: region of its band cells, -1 / -2 as above
 
std::map< int64_t, std::shared_ptr< SampleEnvelope > > m_tag_envelopes
 One containment envelope per input tag, ambient included. Both phases.
 
std::map< int64_t, int > m_tag_bit
 
std::map< uint64_t, std::shared_ptr< SampleEnvelope > > m_isect_cache
 
std::mutex m_isect_mutex
 
std::map< uint64_t, std::shared_ptr< SampleEnvelope > > m_offset_isect_cache
 Memoized "region tubes AND the offset envelope", keyed by the region mask.
 
OptPhase m_phase = OptPhase::A
 Which phase is running. Read by every hook that differs between them; see OptPhase.
 
bool m_freeze_front = false
 The final Phase A: front vertices are not smoothed (see smooth_before()).
 
std::shared_ptr< SampleEnvelope > m_offset_envelope
 The tube the offset surface may not leave during the operation passes, of half-width offset_envelope. Rebuilt after every smoothing pass from the surface as that pass left it, which is what lets the surface travel across turns. Non-null once the offset exists; whether it constrains is containment_for()'s phase test. Unlike m_tag_envelopes, which must never be rebuilt.
 
double m_front_gradient_reference = 0.
 
EdgeSplitMode m_edge_split_mode = EdgeSplitMode::Midpoint
 
std::map< std::string, int64_t > m_tag_name_to_id
 
std::map< int64_t, std::string > m_tag_id_to_name
 
CellTag m_offset_output_tag_ids
 
bool m_singlebody = false
 
int64_t m_single_tag
 
bool m_has_envelope = false
 
MatrixXd m_V_envelope
 
MatrixXi m_F_envelope
 
double m_envelope_eps = -1
 
Parameters & m_offset_params
 The base holds only wmtk::OptimizerParameters; this is the same object, typed.
 
VertexExtraCol m_vertex_extra
 
FaceExtraCol m_face_extra
 
EdgeAttCol m_edge_attribute
 
TetAttCol m_tet_attribute
 
size_t m_worst_dist_vid = static_cast<size_t>(-1)
 
std::atomic< long long > m_offset_face_lookup_misses {0}
 Faces that vertex_has_live_offset_face() / offset_surface_faces_live_at() asked for and the connectivity did not have.
 
std::atomic< long long > m_offset_face_invalid_tuple {0}
 
std::vector< std::array< double, 8 > > optimization_metrics
 
std::vector< std::array< int, 3 > > churn_counts
 
std::vector< std::array< int, 3 > > op_counts
 {splits, collapses, swaps} per turn, as deltas rather than running totals.
 
int m_ab_round = 0
 
size_t m_debug_seq = 0
 Monotonic frame counter for the debug timeline.
 
std::vector< std::string > m_debug_frame_labels
 
std::map< std::string, std::vector< size_t > > m_debug_pvd_series
 
int m_debug_pass = 0
 
int m_debug_last_round = -1
 
char m_debug_last_phase = '?'
 
double m_gradient_reference = 0.
 See offset_gradient_tolerance(). Nothing sets it on the single-phase path; it stays 0.
 
bool m_converged = false
 
bool m_quality_converged = true
 
double m_quality_max_amips = 0.
 
std::atomic< int > iter_cnt_split_born {0}
 
std::atomic< int > iter_cnt_recollapsed {0}
 
std::atomic< int > iter_cnt_recollapsed_same_pass {0}
 
std::atomic< int > iter_cnt_split = 0
 
std::atomic< int > iter_cnt_collapse = 0
 
std::atomic< int > iter_cnt_swap = 0
 
std::atomic< int > iter_cnt_collapse_offset_removed {0}
 
std::atomic< int > iter_cnt_collapse_offset_reject {0}
 Operations refused because they would have left an offset-surface face over tolerance.
 
std::atomic< int > iter_cnt_swap_offset_reject {0}
 
std::atomic< int > iter_cnt_collapse_guard_reject {0}
 
std::atomic< int > iter_cnt_swap_guard_reject {0}
 
std::atomic< long long > flip_trace_n {0}
 accepted offset-surface flips
 
std::atomic< long long > flip_trace_nonmono
 fall < 0 (a rise): MUST stay 0, the rule forbids it
 
std::atomic< long long > flip_trace_bar {0}
 
std::array< std::atomic< long long >, 8 > flip_trace_dec {}
 
std::atomic< long long > funnel_offered {0}
 [flip funnel]: of the flips of the offset surface that passed the sag rule, how many survive each later stage. Reset per turn and reported next to [swap reject].
 
std::array< std::atomic< long long >, 3 > funnel_kind {}
 offered, split by swap kind: [0] = 3-2, [1] = 4-4, [2] = 5-6.
 
std::atomic< long long > funnel_cases {0}
 
std::atomic< long long > funnel_case_inverted {0}
 
std::atomic< long long > funnel_case_not_better {0}
 
std::atomic< long long > funnel_case_better {0}
 
std::atomic< long long > funnel_quality {0}
 
std::atomic< long long > funnel_quality_ok {0}
 
std::atomic< long long > funnel_committed {0}
 
std::atomic< int > iter_cnt_split_offset_before {0}
 Splits of an offset-surface edge: offered, accepted.
 
std::atomic< int > iter_cnt_split_offset {0}
 
std::atomic< long > m_split_order_waits {0}
 
std::atomic< long > m_split_off_longest {0}
 
wmtk::threading::enumerable_thread_specific< OptSplitCache > m_opt_split_cache
 
size_t m_marching_root_splits = 0
 
size_t m_marching_midpoint_splits = 0
 
size_t m_marching_trace_steps = 0
 
size_t m_marching_trace_steps_max = 0
 
SmoothTrace m_smooth_trace
 
optimization::NewtonCounters m_newton_front
 
optimization::NewtonCounters m_newton_plastic
 
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 / fixed / stationary. See TopoOffsetTriMesh::m_needle_pre.
 
std::atomic< size_t > m_needle_smooth_offered {0}
 
std::atomic< size_t > m_needle_smooth_reached {0}
 
std::atomic< size_t > m_needle_smooth_fixed {0}
 
std::atomic< size_t > m_needle_smooth_stationary {0}
 
std::atomic< size_t > m_needle_smooth_reports {0}
 
std::atomic< size_t > m_flat_created_split {0}
 
std::atomic< size_t > m_flat_created_collapse {0}
 
std::atomic< size_t > m_flat_worsened_split {0}
 
std::atomic< size_t > m_flat_genesis_reports {0}
 
wmtk::threading::enumerable_thread_specific< double > m_collapse_parent_flatness
 The flattest tet in the collapse's ring before it ran, for record_flatness().
 
wmtk::threading::enumerable_thread_specific< double > m_collapse_survivor_sizing
 
wmtk::threading::enumerable_thread_specific< std::vector< size_t > > m_collapse_edge_link
 The link of the collapsed edge, captured in collapse_before_vertex().
 
std::atomic< int > m_placement_env_entry_outside {0}
 
std::atomic< int > m_placement_projected {0}
 
std::atomic< int > m_placement_tangential {0}
 
size_t m_front_gradient_worst_vid
 
std::set< int64_t > m_deform_tags
 The released tags. Filled by release_deformable_regions(); empty = feature inactive.
 
std::set< int64_t > m_source_tags
 
std::shared_ptr< SampleEnvelope > m_released_envelope
 
std::atomic< bool > m_released_tube_dirty {false}
 
std::mutex m_released_mutex
 
bool m_plastic_active = false
 set in optimize_offset() when deform_others
 
std::optional< EnergyCriterion > m_energy_verdict
 
std::atomic< size_t > m_deg_split_created {0}
 
std::atomic< size_t > m_deg_collapse_offered {0}
 
std::atomic< size_t > m_deg_collapse_allowed {0}
 
std::atomic< size_t > m_deg_collapse_by_ringmax {0}
 
std::atomic< size_t > m_deg_collapse_by_stop {0}
 
std::atomic< size_t > m_deg_collapse_by_unrounded {0}
 
std::array< size_t, 6 > m_deg_prev_counts {{0, 0, 0, 0, 0, 0}}
 
std::atomic< size_t > m_needle_reports {0}
 
std::set< std::tuple< long, long, long > > m_stuck_prev_cells
 
size_t m_stuck_calls = 0
 
MatrixXd m_phi_V
 
MatrixXi m_phi_E
 
MatrixXi m_phi_F
 
std::vector< int > m_phi_P
 
- Public Attributes inherited from wmtk::TetOptimizerMesh
VertAttCol m_vertex_attribute
 
FaceAttCol m_face_attribute
 
AttributeContainerGroup m_vertex_attr_group
 What p_vertex_attrs points at, so a derived class can register more.
 
AttributeContainerGroup m_face_attr_group
 What p_face_attrs points at, so a derived class can register more.
 
OptimizerParameters & m_params
 
std::shared_ptr< SampleEnvelope > m_envelope
 Surface envelope: what a surface vertex is pulled toward and checked against.
 
double m_s_amips = 1.
 
double m_s_envelope = -1.
 
double time_env = 0.0
 
igl::Timer isout_timer
 
wmtk::threading::enumerable_thread_specific< std::unique_ptr< polysolve::nonlinear::Solver > > m_solver
 Per-thread Newton solver for smoothing; created on first use.
 
optimization::SmoothRejectCounters m_smooth_rejects
 Why smoothing attempts were refused, reported once per pass.
 
optimization::NewtonCounters m_newton
 
bool m_collapse_limit_length = true
 
std::set< simplex::Edge > m_force_split_edges
 
size_t m_force_split_count = 0
 Force-splits taken in the current split pass. Diagnostic only.
 
std::unique_ptr< std::atomic< int >[]> m_high_valence_claim
 Per-pass claims for the shared high-valence split gate.
 
size_t m_high_valence_claim_size = 0
 
std::atomic< size_t > m_high_valence_rejects = 0
 
int m_iterations_used = 0
 Shared TetWild/SimWild outer optimization schedule.
 
int m_debug_print_counter = 0
 
std::string m_debug_pass_name
 
CoarsenStats m_coarsen_stats
 
std::atomic< int > cnt_swap = 0
 
std::atomic< int > cnt_surface_swap = 0
 
std::atomic< int > cnt_surface_swap_32 = 0
 
std::atomic< int > cnt_surface_swap_44 = 0
 
std::atomic< int > cnt_surface_swap_56 = 0
 
- Public Attributes inherited from wmtk::TetMesh
AbstractAttributeContainer * p_vertex_attrs = nullptr
 
AbstractAttributeContainer * p_edge_attrs = nullptr
 
AbstractAttributeContainer * p_face_attrs = nullptr
 
AbstractAttributeContainer * p_tet_attrs = nullptr
 
bool m_collapse_check_link_condition = true
 
bool m_collapse_check_topology = false
 
bool m_collapse_check_manifold = true
 
wmtk::threading::enumerable_thread_specific< std::vector< size_t > > mutex_release_stack
 
wmtk::threading::enumerable_thread_specific< std::vector< size_t > > get_one_ring_cache
 
int NUM_THREADS = 0
 

Static Public Attributes

static constexpr int64_t m_wall_tag = -2
 pseudo-tag: the domain wall's tube
 
static constexpr int64_t m_complex_tag = -3
 
static constexpr int INPUT_SURFACE_CLASS = 0
 SurfaceTagAttributes::m_surface_class: which of the two tracked surfaces a face belongs to. Same scheme as 2D.
 
static constexpr int OFFSET_SURFACE_CLASS = 1
 
static constexpr long long kFlipTraceEvery = 20000
 
static constexpr double kFlatThreshold = 1e-3
 
static constexpr size_t kNeedleReports = 12
 
static constexpr double kNeedleQuality = 1e6
 What counts as a needle for the tripwire, in AMIPS – deliberately far below MAX_ENERGY.
 
- Static Public Attributes inherited from wmtk::TetOptimizerMesh
static constexpr double MAX_ENERGY = 1e50
 The sentinel get_quality returns for an element AMIPS cannot score.
 
- Static Public Attributes inherited from wmtk::TetMesh
static constexpr int EDGES_PER_CELL = 6
 
static constexpr int FACES_PER_CELL = 4
 

Private Member Functions

bool swap_capture_tag (const std::vector< size_t > &tids)
 
bool swap_capture_surface_sides (const std::vector< size_t > &tids, size_t a, size_t b, size_t c, size_t d)
 
bool any_tag_present (const CellTag &tag1, const CellTag &tag2)
 determine if any tag from tag1 is also present in tag2.
 
void sort_edges_by_length (std::vector< simplex::Edge > &edges)
 sort edge simplices in place by decreasing edge length
 

Private Attributes

wmtk::threading::enumerable_thread_specific< EdgeSplitCache > edge_split_cache
 
wmtk::threading::enumerable_thread_specific< FaceSplitCache > face_split_cache
 
wmtk::threading::enumerable_thread_specific< TetSplitCache > tet_split_cache
 
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.
 
wmtk::threading::enumerable_thread_specific< int > m_swap_label
 The construction label shared by every cell of an interior swap's ring, captured alongside.
 
wmtk::threading::enumerable_thread_specific< SwapSurfaceSides > m_swap_sides
 

Additional Inherited Members

- Protected Types inherited from wmtk::TetOptimizerMesh
enum class  SwapReject : int {
  base_before , base_after , valence , bbox ,
  surface_not_allowed , prepare_flip , interior_hook , flip_open_boundary ,
  flip_not_two_surf , flip_nonmanifold_edge , flip_cd_nonmanifold , flip_new_face_surface ,
  flip_app_refused , flip_wrong_case , app_capture_label , app_capture_tag ,
  app_fid_missing , app_class_mismatch , app_mask_mismatch , app_sag_raised ,
  after_inverted , after_quality , after_cells , app_after_side_conflict ,
  app_after_no_side , after_envelope , face_tracked_surface , face_tracked_bbox ,
  face_inverted , face_not_better , COUNT
}
 
enum class  SwapStage : int {
  attempt , surface_attempt , before_pass , after_enter ,
  accepted , COUNT
}
 
enum class  CollapseReject : int {
  coarsen_length , bbox , surface_leaves_envelope , inverted ,
  quality , substructure_link , app_both_surfaces , app_front_unlimited ,
  app_leaves_input , app_leaves_offset , app_leaves_region , app_order2 ,
  app_substructure_link , app_ops_guard , after_base , after_connectivity ,
  after_envelope , after_face_attribute , after_coarsen_region , COUNT
}
 
enum class  SwapRejectRole { before_leaf , after_leaf , wrapper , per_case }
 
- Protected Member Functions inherited from wmtk::TetOptimizerMesh
std::vector< size_t > all_vertex_ids () const override
 Every live vertex, in the mesh's own iteration order.
 
bool vertex_is_rounded (const size_t vid) const override
 Whether this vertex's double position is currently trusted.
 
bool round_vertex (const size_t vid) override
 
virtual void optimization_sanity_checks_extra ()
 
virtual bool optimization_stop_at_float () const
 
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 should therefore fire.
 
bool swap_reject (SwapReject r) const
 
bool swap_reject_kind_only (SwapReject r) const
 
void swap_stage (SwapStage s) const
 
void swap_counters_reset ()
 
std::string swap_reject_report () const
 One line per nonzero counter, for a per-turn log. Does not reset.
 
bool collapse_reject (CollapseReject r) const
 
std::string op_accounting_report (OpKind k) const
 
bool op_accounting_unexplained (OpKind k) const
 True when the report for k has a nonzero remainder: a refusal no counter named.
 
void op_accounting_reset ()
 
OpHookReasons op_hook_reasons (OpKind k) const
 
long op_event_count (const OpKind k, const OpEvent e) const
 
long op_unaccounted (OpKind k) const
 Attempts minus every outcome: 0 unless an exit of the TetMesh operation reports nothing.
 
- Protected Member Functions inherited from wmtk::TetMesh
virtual bool triangle_insertion_before (const std::vector< Tuple > &faces)
 
virtual bool triangle_insertion_after (const std::vector< std::vector< Tuple > > &)
 
void resize_vertex_mutex (size_t v)
 
- Static Protected Member Functions inherited from wmtk::TetOptimizerMesh
static const char * swap_reject_name (SwapReject r)
 
static const char * swap_stage_name (SwapStage s)
 
static const char * collapse_reject_name (CollapseReject r)
 
static OpKind & current_op_kind ()
 
static const char * op_kind_name (OpKind k)
 
static const char * op_event_name (OpEvent e)
 
static SwapRejectRole swap_reject_role (SwapReject r)
 
- Protected Attributes inherited from wmtk::TetOptimizerMesh
uint32_t m_op_epoch = 0
 
std::array< std::atomic< long >, size_t(SwapReject::COUNT)> m_swap_reject {}
 
std::array< std::atomic< long >, size_t(SwapStage::COUNT)> m_swap_stage {}
 
std::array< std::atomic< long >, size_t(CollapseReject::COUNT)> m_collapse_reject {}
 
std::array< std::array< std::atomic< long >, size_t(OpEvent::COUNT)>, size_t(OpKind::COUNT)> m_op_events {}
 
std::array< std::array< std::atomic< long >, size_t(SwapReject::COUNT)>, size_t(OpKind::COUNT)+1 > m_swap_reject_by_kind {}
 
wmtk::threading::enumerable_thread_specific< SwapInfoCache > swap_cache
 
wmtk::threading::enumerable_thread_specific< SplitInfoCache > split_cache
 
wmtk::threading::enumerable_thread_specific< CollapseInfoCache > collapse_cache
 
bool m_coarsen_mode = false
 Set for the duration of coarsen_mesh(); read-only while a pass is running.
 
- Protected Attributes inherited from wmtk::RationalPositions
std::atomic< bool > m_all_rounded = false
 True when every vertex is known to be rounded.
 

Detailed Description

The offset's tet mesh, on the shared 3D optimizer.

Mirrors TopoOffsetTriMesh one dimension up: the construction phase (simplicial embedding, marching tets, growing the band) is entirely its own, and the optimization phase that follows is wmtk::TetOptimizerMesh's, with the offset supplying only policy through the hooks.

Two surfaces are tracked. Every tag-region boundary (input complex and domain wall included) keeps the primary class 0 and is held in its tags' envelopes, as tetwild holds its input; the offset surface is OFFSET_SURFACE_CLASS, the faces across which the incident tet labels differ. Class-0 faces may move within their tubes; only the offset one is driven toward target_distance.

Member Enumeration Documentation

◆ EnvelopeSetup

Which boundaries the region-class envelopes hold, and how they are built.

PerTag (deform_others false): one exact tube per input tag around that tag's boundary triangles, the domain wall in the tags of its wall tets. A vertex carries the bit of every tube it lies on and is contained in their intersection, so every region boundary – the input complex and the wall included – is held.

WallComplex (deform_others true): exactly two tubes, the domain wall and the boundary of the input complex (any dimension, any manifoldness: it is a set of triangles), under the pseudo-tags m_wall_tag / m_complex_tag. Every other region boundary carries no bit and is held by nothing; the medium around it is plastic, see cell_is_plastic().

Either way build_boundary_envelopes() derives the masks and tubes from the mesh as it stands when called: at load (PerTag, before the complex is labelled), when deform_others switches the setup at construction, and fresh at the start of the final pass. The offset tube is separate and unchanged.

◆ OptPhase

Which mode the hooks are running in. The 3D copy of TopoOffsetTriMesh::OptPhase.

A: TetWild's loop and nothing else – today only the frozen-front final pass – with m_offset_envelope holding the front. B: the front objective's offset terms are live; set only around measurements (the criterion, the gradient reference) so they see the objective the placement uses. Single: the run's loop, TetWild's operation groups with the front placed by B's objective inside the smoothing passes – B wherever the smoother is concerned (objective, no offset tube while the front moves), A wherever the loop is (quality stats, stop metric).

Member Function Documentation

◆ allow_surface_swap()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::allow_surface_swap ( ) const
inlineoverridevirtual

Surface edges may be flipped, as a topology-preserving diagonal flip. Both tracked surfaces need it: the offset surface is re-triangulated constantly.

Implements wmtk::TetOptimizerMesh.

◆ any_tag_present()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::any_tag_present ( const CellTag &  tag1,
const CellTag &  tag2 
)
inlineprivate

determine if any tag from tag1 is also present in tag2.

Note
if tag2 is empty (ambient), return true if tag1 is empty, otherwise false

◆ assign_band_regions()

void wmtk::components::topological_offset::TopoOffsetTetMesh::assign_band_regions ( bool  log = true)

Rebuild m_*_region from the mesh. log false suppresses the per-turn "[regions]" line: write_vtu() re-derives the map for its frame diagnostics and puts the old one back.

◆ audit_surface_containment()

void wmtk::components::topological_offset::TopoOffsetTetMesh::audit_surface_containment ( const std::string &  when) const

Which tracked faces are outside their envelope, and by how much, per real member tube. Diagnostic only; the 3D twin of the 2D function of the same name.

< furthest sample distance to a real member tube

< furthest CORNER distance – 0 means every corner is inside

< worst sample distance over eps; 1.0 is the skin

< over EVERY measured face; snug only keeps those at 0.9+

◆ band_vertex_is_reachable()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::band_vertex_is_reachable ( const size_t  vid) const
inline

Whether vid is a band vertex the optimizer could still place at target_distance. An envelope-held offset vertex is pinned, as is one on the domain boundary. Same rule as 2D.

◆ build_boundary_envelopes()

void wmtk::components::topological_offset::TopoOffsetTetMesh::build_boundary_envelopes ( const char *  when,
EnvelopeSetup  setup 
)

Rebuild every region-class tube and every vertex's boundary mask from the current mesh under setup. PerTag at load (the complex is not labelled yet), WallComplex when deform_others switches it at construction, envelope_setup() fresh at the final pass. The tracked-face flags are left alone: they are the topology the operations maintain. when labels the log line.

◆ cell_in_region()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::cell_in_region ( const size_t  tid) const
inline

Whether tet tid belongs to the closed offset region, read from its label: the band (label 2) plus the input complex it wraps (label 1). Every operation carries the label onto the cells it creates, so this is exact; tags cannot express the distinction.

◆ cell_is_released_band()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::cell_is_released_band ( size_t  tid) const

A band cell that is a released object's material: every non-output tag released, at least one present.

◆ cell_quality()

double wmtk::components::topological_offset::TopoOffsetTetMesh::cell_quality ( const size_t  tid) const
inlineoverridevirtual

The quality of cell tid, and how to write it.

The cell attribute types differ between the applications, so the base reaches the one field it shares through these. Both are AMIPS^3; see MAX_ENERGY. Topological operations and smoothing use the accessors so the shared algorithms remain independent of each application's cell-attribute type.

Implements wmtk::TetOptimizerMesh.

◆ check_no_vertex_on_both_surfaces()

void wmtk::components::topological_offset::TopoOffsetTetMesh::check_no_vertex_on_both_surfaces ( const char *  when) const

Hard error if any vertex is on both the input complex and the offset surface – a state no placement satisfies. Called at construction and after every phase.

◆ check_offset_membership()

void wmtk::components::topological_offset::TopoOffsetTetMesh::check_offset_membership ( const char *  when) const

Log offset_membership_mismatches() and throw when it is not {0, 0}. perform_sanity_checks only.

◆ check_offset_within_support()

void wmtk::components::topological_offset::TopoOffsetTetMesh::check_offset_within_support ( const char *  when) const

Stop the run if any reachable band vertex has left the potential's support. Called once per turn and once on the band as constructed.

◆ check_surface_topology()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::check_surface_topology ( ) const
inlineoverridevirtual

◆ classify_sheet_faces()

void wmtk::components::topological_offset::TopoOffsetTetMesh::classify_sheet_faces ( )

Mark the mesh faces that lie on the input's envelope surface group (FaceExtra::on_sheet).

Geometric, against the sheet's own tube (the same eps the tag envelopes use), because the .msh carries the sheet with its own vertices and there is no index to match on. Called whenever the complex is labelled, not once at load: the flag is a property of a face and nothing propagates it through split and collapse.

◆ collapse_after_connectivity()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_after_connectivity ( size_t  v1,
size_t  v2,
const std::vector< std::array< size_t, 2 > > &  boundary_edges 
)
overridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_after_vertex()

void wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_after_vertex ( size_t  v1,
size_t  v2 
)
overridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_before_vertex()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_before_vertex ( size_t  ,
size_t  ,
double   
)
overridevirtual

Non-const: an override may cache what it measured before the collapse so its after counterpart can tell a regression from a defect that was already there.

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_edge_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_edge_after ( const Tuple &  t)
overridevirtual

The coarsening bar, the sizing restore and the rest re-stamp, after the base accepted.

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_edge_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_edge_before ( const Tuple &  t)
overridevirtual

Reject any collapse that violates the substructure link condition, and remember the survivor's sizing for sizing_collapse_min = false.

The base applies the link condition only when both endpoints already sit on a tracked surface or the bbox; the offset region is a thin shell, so a collapse with one endpoint in the interior can still pinch its two sides together. The offset asks unconditionally.

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_is_order_2_edge()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_is_order_2_edge ( const std::array< size_t, 2 > &  e)
inlineoverridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ collapse_quality_allowed()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::collapse_quality_allowed ( size_t  v1,
double  q,
double  ring_max 
) const
overridevirtual

Instrumentation only: which operation manufactures the MAX_ENERGY needles.

Reimplemented from wmtk::TetOptimizerMesh.

◆ compute_distance_deviation()

std::pair< double, double > wmtk::components::topological_offset::TopoOffsetTetMesh::compute_distance_deviation ( ) const

How far the offset surface is from where it should be: {max, avg} over vertices.

The absolute error |dist(v, input complex) - target_distance| over the offset-surface vertices only, pinned ones included. Mirrors TopoOffsetTriMesh::compute_distance_deviation().

◆ containment_for()

std::shared_ptr< SampleEnvelope > wmtk::components::topological_offset::TopoOffsetTetMesh::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 intersection of everything that holds it, or null if nothing does.

The single place the two containment families are composed. region_mask dispatches through envelope_for_mask(); on_offset adds m_offset_envelope, but only in Phase A – the phases that place the front are what move the offset surface, so there the result is the region tubes alone.

◆ edge_conv_ratio()

double wmtk::components::topological_offset::TopoOffsetTetMesh::edge_conv_ratio ( size_t  a,
size_t  b 
) const

The chord twin of face_conv_ratio(): the RMS relative error over the chord's two endpoints and its midpoint, over the same bar; -1 unmeasurable. NO CALLERS in 3D.

◆ envelope_for_mask()

std::shared_ptr< SampleEnvelope > wmtk::components::topological_offset::TopoOffsetTetMesh::envelope_for_mask ( uint64_t  mask) const

The envelope a simplex with this boundary mask is contained in, or null. Zero bits: no container. One bit: that tag's envelope. Several: a memoized IntersectionEnvelope, which is containment-only and must never be returned from smoothing_energy_envelope().

◆ execute_offset()

void wmtk::components::topological_offset::TopoOffsetTetMesh::execute_offset ( const std::filesystem::path &  output_file)

Construction, start to finish, on the input mesh as given: the simplicial embedding, marching_tets(), the re-embedding and the offset tagging. The optimization is optimize_offset(), which the driver calls afterwards.

◆ face_borders_released_boundary()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::face_borders_released_boundary ( const Tuple &  f) const

Whether this face lies on a released region's boundary, by the incident tets' current tag symmetric difference – the same test the release freed vertices by.

◆ face_boundary_bits()

uint64_t wmtk::components::topological_offset::TopoOffsetTetMesh::face_boundary_bits ( const Tuple &  f) const
inline

Diagnostic only: which tag boundaries the incident tets say this face lies on right now – the same symmetric difference init_surfaces_and_boundaries() classified by. Only trustworthy while the tet tags are still the input's own.

◆ face_conv_ratio()

double wmtk::components::topological_offset::TopoOffsetTetMesh::face_conv_ratio ( size_t  a,
size_t  b,
size_t  c 
) const

THE FACE MEASURE, and the ONE function every reader of it calls: energy_criterion()'s exit, refinement and ring measures, the ops guards through face_resolution_or_inf() and vertex_ring_measure(), and the debug frames' front_err_ratio and front_ring_ratio. As a ratio to THE bar front_conv (1 = the bar): the ROOT MEAN SQUARE over the face's stencil_order stencil of OffsetPotential::relative_residual(q), the distance to the level set along the field over target_distance (for the euclidean field (Phi(q) - c)/c, for the smooth field not – see face_conv_ratio()'s definition). Since the stencil contains the CORNERS, this one number answers both questions the loop used to ask separately – a face is resolved when it is <= 1, and a vertex is placed when the same measure over its own point (front_vertex_conv_ratio(), the order-0 stencil at one corner) is <= 1. < 0 when not measurable, i.e. any sample where relative_residual() is not finite.

◆ face_criterion_rel()

double wmtk::components::topological_offset::TopoOffsetTetMesh::face_criterion_rel ( const Tuple &  f) const

Max of the two normalized criteria (AMIPS over stop, residual over tolerance) on this face; >= 1 means it fails at least one. The coarsen-mode collapse accept reads it.

◆ face_is_complex_boundary()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::face_is_complex_boundary ( const Tuple &  f) const

Whether this face lies on the boundary of the input complex: exactly one incident tet carries label 1, or the face itself does while neither tet does (a sheet or face piece).

◆ face_is_offset()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::face_is_offset ( const size_t  fid) const
inline

Whether face fid is on the offset surface / bounds a region – any tracked face that is not the offset surface. The input complex is included, and deliberately: both are held by the same per-tag envelopes and neither is what the optimization moves.

◆ face_is_offset_surface_live()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::face_is_offset_surface_live ( const Tuple &  f) const

The band's outer surface, recomputed live rather than read from the cached class.

A band cell meeting a cell that is neither band nor input complex. Must be live: the operations that ask run between one labelling pass and the next. Returns true for a band face on the domain boundary, whose vertices are pinned and must be measured, not hidden. The 2D twin is edge_is_offset_surface_live().

◆ face_is_on_surface()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::face_is_on_surface ( const size_t  fid) const
overridevirtual

Is a face part of the substructure.

Parameters
fidFace ID

Reimplemented from wmtk::TetOptimizerMesh.

◆ face_mask()

uint64_t wmtk::components::topological_offset::TopoOffsetTetMesh::face_mask ( const std::array< size_t, 3 > &  vids) const
inline

A face lies on a boundary only if all of it does: the AND of its corners' masks. The 3D twin of edge_mask(), which ANDs two.

◆ face_resolution_or_inf()

double wmtk::components::topological_offset::TopoOffsetTetMesh::face_resolution_or_inf ( size_t  a,
size_t  b,
size_t  c 
) const

The ops divergence guard: one face's measure as face_conv_ratio() gives it, with an unmeasurable face reported as infinity so that losing measurability counts as worsening.

◆ for_each_face_sample()

template<typename Visit >
void wmtk::components::topological_offset::TopoOffsetTetMesh::for_each_face_sample ( const Vector3d &  p0,
const Vector3d &  p1,
const Vector3d &  p2,
Visit &&  visit 
) const
inline

The interior lattice a triangle is sampled on, handed to visit one point at a time as (point, wa, wb, wc) with the barycentric weights that built it: every (i, j, l) with i + j + l = k + 2 and each >= 1, so k = 1 is the centroid alone and the counts are 1, 3, 6, 10 for k = 1..4. Strictly interior – no sample ever lands on an edge or a corner, where the interpolant is exact by construction and the sag is identically zero.

The weights are handed out because the sag at a sample is measured against the LINEAR INTERPOLANT there, wa*Va + wb*Vb + wc*Vc, which is only the plain mean of the corners at the centroid. See face_conv_ratio().

Takes positions rather than a Tuple so the ops guard can measure a face the mesh does not carry yet (a collapse's predicted face, one corner relabelled). The 2D twin is for_each_offset_edge_sample().

◆ front_chord_target()

double wmtk::components::topological_offset::TopoOffsetTetMesh::front_chord_target ( size_t  va,
size_t  vb,
double  len,
double  sag,
double  tube 
) const

The edge length that would bring a front chord's sag under the tube: 3/4 L (tube / sag)^(1/p) capped at L/2, with the exponent p measured from how the level set turns across the chord. Same formula as 2D.

Reached from ONE place now: the refinable / at-floor test in energy_criterion(), which asks whether there is any target left below what the face's corners already carry.

◆ front_move_alignment()

double wmtk::components::topological_offset::TopoOffsetTetMesh::front_move_alignment ( size_t  vid) const

|cos| between front_vertex_move_direction() and the field normal: 1 means the convergence test's 1-D step is the step toward the level set, 0 means it measures a direction that cannot reduce the distance. Debug-frame diagnostic; see write_vtu().

◆ front_placed_by_ratio()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::front_placed_by_ratio ( const double  ratio) const
inline

front_vertex_placed()'s decision on an already-measured ratio, for the callers that have one in hand (energy_criterion(), the guards' snapshot, SmoothingProgress): the one place the bar is applied. Keep this and front_vertex_placed() in step.

◆ front_vertex_alignment_traps_1d_solve()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::front_vertex_alignment_traps_1d_solve ( size_t  vid) const

Whether the 1-D placement at vid is trapped by the alignment term: a live front face at or past perpendicular to the field AND the alignment term's 1-D gradient opposing the placement term's along the move direction, at a vertex stationary off its level set.

◆ front_vertex_conv_ratio()

double wmtk::components::topological_offset::TopoOffsetTetMesh::front_vertex_conv_ratio ( size_t  vid) const

The vertex's convergence measure divided by its bar, per front_conv_criterion: 1 is the bar. See the spec entry for the four measures – three of stationarity, plus residual_error, which measures the residual length instead. Infinite when unmeasurable.

◆ front_vertex_move_direction()

Vector3d wmtk::components::topological_offset::TopoOffsetTetMesh::front_vertex_move_direction ( size_t  vid) const

The line a front vertex is placed along: the field normal, or that normal projected into the boundary surface (onto its crease) where an input envelope holds it.

◆ front_vertex_normal_gradient()

double wmtk::components::topological_offset::TopoOffsetTetMesh::front_vertex_normal_gradient ( size_t  vid) const

||grad F|| at front vertex vid along its move direction, F the objective smooth_front_vertex_phase_b() minimises. +inf if unmeasurable.

◆ front_vertex_placed()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::front_vertex_placed ( size_t  vid) const

THE definition of "placed" for a vertex on the offset surface.

Every decision in the component that asks "is the placement of this front vertex done" goes through here or through front_placed_by_ratio(): the vertex measure the loop reports (EnergyCriterion::vertices_ok(), a diagnostic since 2026-09-25 – the loop exits on the face measure), the corner qualification of the face-sag classification, the collapse and swap guards' snapshot and the collapse guard's after-half, the adaptive-smoothing stop, and the alignment-trap test. One notion, chosen by front_conv_criterion, so a vertex cannot be placed for one of them and not for another.

It was not always one notion: the sag classification used to qualify its corners with the DISTANCE to the level set (residual_length() within front_conv) while everything else used the criterion's stationarity measure. The two disagree exactly where it matters – a vertex whose Newton step has collapsed sits wherever it sits, and one a hair outside the tube disqualified its whole face from ever being refined, with the face then counted in neither refinable nor n_at_floor and so invisible to the exit test of the time (converged_single(), removed 2026-09-25). Measured in 2D on top_annots_uday: at turn 1, 50 of the 114 sagging chords were dropped that way, the worst of them sagging 74 tubes, because one end sat 1.02 tubes off the level set with a Newton step of 1e-9. * front_conv_criterion "residual_error" makes that same residual_length() the measure for every one of the callers above. That is not the defect coming back: the defect was the SPLIT – one test using the residual while the rest used stationarity – not the use of the residual. Under residual_error both halves of the criterion, the vertex test and the chord/face sag, are lengths against rel x target_distance.

The caller has established that vid is a live front vertex (m_is_on_offset && m_is_rounded); this does not re-check that. Unmeasurable (a non-finite ratio) is NOT placed.

◆ get_order_of_vertex()

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::get_order_of_vertex ( const size_t  vid) const
overridevirtual

Get the order of a vertex.

The order of a vertex in a TetMesh is as follows: 0: vertex is not on the surface 1: vertex is on the surface 2: vertex is on the surface boundary or a non-manifold edge 3: vertex is at the boundary of a non-manifold edge or a non-manifold vertex

Computing the vertex order is expensive. It is recommended to store the vertex order as a vertex attribute and override this method.

Parameters
vidVertex ID

Reimplemented from wmtk::TetOptimizerMesh.

◆ grade_sizing()

void wmtk::components::topological_offset::TopoOffsetTetMesh::grade_sizing ( double  grade,
const std::vector< size_t > &  seeds 
)

Spread the refinement just made at seeds to the vertices around them, the way sizing_gradation_mode says: "ring" is the base gradation_smooth_sizing(grade, seeds), "distance" is grade_sizing_by_distance(seeds) and ignores grade. Every place the offset lowers the field goes through here.

◆ grade_sizing_by_distance()

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::grade_sizing_by_distance ( const std::vector< size_t > &  seeds)

TetWild's gradation, ported from tetwild::TetWild::adjust_sizing_field: a breadth-first walk out of the seeds over mesh neighbours; every vertex reached within R = 1.8 l of its nearest seed has its scalar multiplied by 0.5 + 0.5 dist / R, the walk stops at vertices farther than R, and the result is floored at the sizing floor. The seeds themselves keep the scalar the caller gave them. Returns the number of vertices lowered.

◆ gradient_split()

TopoOffsetTetMesh::GradientSplit wmtk::components::topological_offset::TopoOffsetTetMesh::gradient_split ( bool  include_face_samples = true) const
Parameters
include_face_samplesfalse skips the face-interior half (the expensive one).

◆ init_from_image()

void wmtk::components::topological_offset::TopoOffsetTetMesh::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

Parameters
V#V by 3 vertex matrix
T#T by 4 tet matrix
T_tags#T by #tags tag matrix
V_envV_env by 3 EnvelopeSurface vertices
F_envF_env by 3 EnvelopeSurface faces

◆ init_surfaces_and_boundaries()

void wmtk::components::topological_offset::TopoOffsetTetMesh::init_surfaces_and_boundaries ( )

Classify every region boundary, build the per-tag containment envelopes, and tag the domain wall – once, from the input mesh, before offset construction runs.

A region boundary is a face whose two incident tets carry different tag sets; it enters the bucket of every tag on exactly one side (the symmetric difference). A face with only one incident tet is the domain wall and enters its single tet's tags' buckets, which is how ambient's envelope comes to hold the box.

◆ invariants()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::invariants ( const std::vector< Tuple > &  tets)
overridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ is_edge_on_region()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::is_edge_on_region ( const Tuple &  loc)

Whether edge loc lies on a region boundary / on the offset surface, by the cached face classes.

◆ is_open_boundary_edge()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::is_open_boundary_edge ( const Tuple &  e)
inlineoverridevirtual

The offset's surface can end on a non-manifold or boundary edge of the input complex, which the base must not flip or split across.

Reimplemented from wmtk::TetOptimizerMesh.

◆ label_offset_boundary()

void wmtk::components::topological_offset::TopoOffsetTetMesh::label_offset_boundary ( )

Tag the two tracked surfaces for the optimization phase.

The offset surface is the faces across which the incident tet labels differ, so it falls out of the labelling and is recomputed here once. The 2D twin is TopoOffsetTriMesh::label_offset_boundary().

◆ log_refine_block_census()

void wmtk::components::topological_offset::TopoOffsetTetMesh::log_refine_block_census ( const std::string &  when,
double  filter_energy 
) const

For every element above filter_energy, why its edges cannot be split: short / valence / contain / free. The 3D twin of log_refine_block_census().

◆ log_region_face_mask_health()

void wmtk::components::topological_offset::TopoOffsetTetMesh::log_region_face_mask_health ( const std::string &  when) const

Are the tracked region boundaries actually contained by anything? The 3D twin of log_region_edge_mask_health(): a class-0 face whose corners' masks AND to zero is held by nothing. Called at construction and at each turn so the two can be compared.

◆ log_smoothing_pass_accounting()

void wmtk::components::topological_offset::TopoOffsetTetMesh::log_smoothing_pass_accounting ( )
overridevirtual

Called by smooth_all_vertices() after each pass's own accounting lines: an application that solves some vertices on a path of its own logs, and then resets, its counters here.

Reimplemented from wmtk::TetOptimizerMesh.

◆ log_stuck_refine_census()

void wmtk::components::topological_offset::TopoOffsetTetMesh::log_stuck_refine_census ( double  max_metric,
double  filter_energy 
)

Why Phase A is stuck: a census of the tets stuck-refine is about to chase. The 3D twin of log_stuck_refine_census().

◆ marching_split_edge_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::marching_split_edge_after ( const Tuple &  t)

check inversion & rounding

◆ marching_tets()

void wmtk::components::topological_offset::TopoOffsetTetMesh::marching_tets ( )

Marching tets: every edge with one endpoint in the input complex (label 1/2) and the other in the background (label 0) is split – at the midpoint, or under sphere_trace_initialization where d(x) = target_distance along the edge (see edge_split_sphere_trace()) – and afterwards every background tet still touching a complex frontier vertex (the split-off halves) becomes the band (label 2).

◆ mark_input_complex_vertices()

void wmtk::components::topological_offset::TopoOffsetTetMesh::mark_input_complex_vertices ( )

Set VertexExtra::m_is_on_input from the construction labels, once label_input_complex() has evaluated the selection. The 2D twin has the same name.

◆ max_band_vertex_distance()

double wmtk::components::topological_offset::TopoOffsetTetMesh::max_band_vertex_distance ( ) const

The furthest any offset-surface vertex sits from the input complex, by BVH. 0 when no offset exists yet. Sizes dhat in init_offset_potential().

◆ offset_face_samples()

TopoOffsetTetMesh::FaceSamples wmtk::components::topological_offset::TopoOffsetTetMesh::offset_face_samples ( const Tuple &  f) const

The Phi residual at the stencil_order stencil's points of offset face f. Returns nothing for a face with an unreachable corner. The 2D twin is offset_edge_samples().

◆ offset_gradient_tolerance()

double wmtk::components::topological_offset::TopoOffsetTetMesh::offset_gradient_tolerance ( ) const
inline

The gradient_norm_rel bar: front_conv_frac() x a measured reference (m_gradient_reference, never measured on the single-phase path, so this sits at the floor there; the single-phase bar uses m_front_gradient_reference instead). The fraction rather than the length, because the reference is a gradient, not a distance. Same as 2D.

◆ offset_membership_mismatches()

std::pair< size_t, size_t > wmtk::components::topological_offset::TopoOffsetTetMesh::offset_membership_mismatches ( ) const

perform_sanity_checks: how many vertices carry m_is_on_offset without a live offset face, and how many are the other way round. Whole-mesh, O(V x ring); zero is the invariant.

◆ offset_residual_tolerance()

double wmtk::components::topological_offset::TopoOffsetTetMesh::offset_residual_tolerance ( ) const
inline

The residual scale, derived from the criterion: half the gradient tolerance over the level-set slope squared, in length units. Same expression as 2D.

◆ offset_surface_edges()

std::vector< std::array< size_t, 2 > > wmtk::components::topological_offset::TopoOffsetTetMesh::offset_surface_edges ( ) const

Every edge of the live offset surface, once. What the chord test and the alignment term enumerate; the 2D twin walks get_edges() and asks edge_is_offset_surface_live().

◆ offset_surface_foldover_labels()

std::vector< char > wmtk::components::topological_offset::TopoOffsetTetMesh::offset_surface_foldover_labels ( ) const

Per-vertex 0/1: is this vertex an endpoint of a COLLAPSED (folded-over) offset surface edge? Debug-frame diagnostic; see write_vtu(). Costs one pass over the live offset faces, no field evaluation.

An offset-surface edge carries two live offset faces. Measured through either side, the angle between them is 180 degrees where the surface is flat and 360 where the two faces lie on top of each other with that side pinched to nothing. Over FOLDOVER_OUTER_ANGLE_DEG through EITHER side is the fold, and every such edge's two endpoints get 1.

Which side is pinched is deliberately not determined: on the cube the measured folds pinch the BACKGROUND, not the band, so a test written around a pinched band found none of them. Since the two sides sum to 360, the test is simply that the unsigned angle is under 360 minus the threshold. Vertices of an edge that does not carry exactly two live offset faces are left 0, as are degenerate faces: this is a diagnostic, and a number it cannot measure is not a fold.

The 2D twin is TopoOffsetTriMesh::offset_surface_foldover_labels(), which asks the same question of a curve vertex's two incident offset edges.

◆ offset_vertex_normal()

Vector3d wmtk::components::topological_offset::TopoOffsetTetMesh::offset_vertex_normal ( const size_t  vid) const

The normal at an offset vertex: the unit vector from the nearest point on the input complex to the vertex. Zero where undefined. Same definition as 2D.

◆ op_event()

void wmtk::components::topological_offset::TopoOffsetTetMesh::op_event ( OpKind  k,
OpEvent  e 
) const
overridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ ops_guard_measures()

std::pair< double, double > wmtk::components::topological_offset::TopoOffsetTetMesh::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

THE ops guards' comparison, one implementation for the collapse and the swap guard: {before, after}, the largest measure among the elements the operation changes, the element being what the exit tests under front_measure. before holds the offset faces the operation changes as they are, after what replaces them (the collapse's relabelled ring, the swap's two new faces), removed the vertex the operation deletes (-1 none). "face": the changed faces themselves, face_resolution_or_inf(). "vertex_ring": every corner of a changed face – the vertices whose rings change – with vertex_ring_measure() over the ring as it is and as it will be. See the definition for why "face" compares the changed faces and not the vertices around them.

◆ ops_guard_refuses_collapse()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::ops_guard_refuses_collapse ( size_t  v1,
size_t  v2 
) const

The guard's collapse test, run from collapse_edge_before(); see the key's spec doc. Returns true when the collapse must be refused. Applies ONLY where edge (v1, v2) lies exactly on the offset surface, which it checks first and cheaply: everything else returns false without walking a one-ring or evaluating a potential. There is no after-half: the survivor keeps its position, so the result is measured exactly before the collapse runs.

◆ optimization_bare_coarsen_passes()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::optimization_bare_coarsen_passes ( ) const
inlineoverridevirtual

TetWild's bare collapse passes are off for the offset, as TriWild's are in 2D: with no length gate the quality test alone demolishes the band, and the sizing field cannot refuse a collapse.

Reimplemented from wmtk::TetOptimizerMesh.

◆ optimization_quality_stats()

std::tuple< double, double > wmtk::components::topological_offset::TopoOffsetTetMesh::optimization_quality_stats ( )
overridevirtual

The loop's quality metric: TetWild's own outside Phase B, the max of AMIPS and the Phi residual (each over its own target) in Phase B. See the 2D twin.

Reimplemented from wmtk::TetOptimizerMesh.

◆ optimization_stop_metric()

double wmtk::components::topological_offset::TopoOffsetTetMesh::optimization_stop_metric ( ) const
inlineoverridevirtual

stop_energy outside Phase B, 1.0 in it – in the same units as the line above.

Reimplemented from wmtk::TetOptimizerMesh.

◆ phase_b_front_energy()

std::shared_ptr< polysolve::nonlinear::Problem > wmtk::components::topological_offset::TopoOffsetTetMesh::phase_b_front_energy ( size_t  vid,
const std::shared_ptr< const OffsetPotential3D > &  pot 
) const

The two offset terms for a front vertex: the zeroth-order OffsetEnergy3D and the first-order AlignEnergy3D (one residual per incident live front face). Defined in FrontSmooth3d.cpp.

◆ phase_b_front_gradient_linf()

double wmtk::components::topological_offset::TopoOffsetTetMesh::phase_b_front_gradient_linf ( )

Max over the front vertices of the vertex convergence measure (a ratio to its bar); under gradient_norm_rel and before the reference exists, the raw |n . grad F|. The pass stop.

◆ phase_b_front_objective()

std::shared_ptr< polysolve::nonlinear::Problem > wmtk::components::topological_offset::TopoOffsetTetMesh::phase_b_front_objective ( size_t  vid,
const Vector3d &  x 
) const

The Phase B objective of front vertex vid with the vertex at x: AMIPS of its one-ring + phase_b_front_energy(). What the measure above differentiates.

◆ phase_places_front()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::phase_places_front ( ) const
inline

Whether the smoother places front vertices against the offset objective: Phase B, and the single-phase mode that does the same thing inside TetWild's passes.

◆ potential_ptr_for()

std::shared_ptr< const OffsetPotential3D > wmtk::components::topological_offset::TopoOffsetTetMesh::potential_ptr_for ( const size_t  vid) const
inline

The same selection as potential_for(), as the pointer the energies take a share of. Null only when m_offset_potential is, which the front placement paths test for.

◆ rebuild_offset_envelope()

void wmtk::components::topological_offset::TopoOffsetTetMesh::rebuild_offset_envelope ( )

Rebuild m_offset_envelope from the current offset-surface faces, and drop the intersections memoized against the old one.

◆ refine_front_by_halving() [1/2]

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::refine_front_by_halving ( const std::vector< EnergyCriterion::Refinable > &  faces)

THE refinement: halve the sizing scalar at the corners of every refinable face, once per vertex per call, floored at max(min_sizing_scalar, min_edge_length / l), then graded outward. Returns the number of vertices lowered.

◆ refine_front_by_halving() [2/2]

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::refine_front_by_halving ( const std::vector< size_t > &  vertices)

The same halving at the listed vertices themselves: each lowered once per call, floored, then graded. The face form above is this on its faces' corners, in the order given; front_measure "vertex_ring" calls it directly with the vertices whose ring measure is over the bar.

◆ refine_sizing_around_worst()

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::refine_sizing_around_worst ( double  max_metric)
overridevirtual

TetWild's stall-driven sizing refinement, verbatim; Phase A only. See the 2D twin.

Implements wmtk::TetOptimizerMesh.

◆ refresh_offset_membership()

void wmtk::components::topological_offset::TopoOffsetTetMesh::refresh_offset_membership ( size_t  vid)

Re-derive m_is_on_offset for one vertex from the cell labels, exactly.

THE definition of the flag, and the only thing that writes it after label_offset_boundary(): a vertex is on the offset surface iff some incident face has the band on one side and a non-complex cell on the other. Called from the three hooks where an operation can change the answer – see the note above m_collapse_edge_link.

Reads labels, never the flag it is writing and never the cached face class, so a wrong value cannot propagate and any vertex an operation touches is corrected whatever it carried before.

It deliberately does NOT touch m_vertex_attribute[vid].m_is_on_surface, which is the base's union over every tracked surface (input, region, offset); clearing that from here would unhold a vertex that is still on a region boundary. See the CLAUDE.md note.

◆ release_deformable_regions()

void wmtk::components::topological_offset::TopoOffsetTetMesh::release_deformable_regions ( )

Drop the released tags' envelopes and stamp every deformable cell's rest. Called once from optimize_offset() when deform_others is set.

◆ released_envelope()

std::shared_ptr< SampleEnvelope > wmtk::components::topological_offset::TopoOffsetTetMesh::released_envelope ( ) const

The current released-boundary tube, rebuilt first if dirty. Null when nothing is released or no released-boundary face exists.

◆ report_offset_face_lookup_misses()

void wmtk::components::topological_offset::TopoOffsetTetMesh::report_offset_face_lookup_misses ( const char *  when) const

Log the two counters above, run totals, and only when either is non-zero – a clean run prints nothing. Not gated on perform_sanity_checks: these are free unless they fire.

◆ rest_energy_for_vertex()

std::shared_ptr< polysolve::nonlinear::Problem > wmtk::components::topological_offset::TopoOffsetTetMesh::rest_energy_for_vertex ( size_t  vid) const

The rest-shape AMIPS over the deformable cells of vid's one-ring, weighted like the shared smoother weights its AMIPS term; null when the ring has none.

◆ ring_face_area()

double wmtk::components::topological_offset::TopoOffsetTetMesh::ring_face_area ( size_t  a,
size_t  b,
size_t  c 
) const

An offset face's area from its current corners: its weight in the ring measure. Read by energy_criterion(), vertex_ring_measure() and the debug frames alike.

◆ ring_max_quality()

double wmtk::components::topological_offset::TopoOffsetTetMesh::ring_max_quality ( size_t  vid) const

Max AMIPS (the cube root of the stored cell quality) over the tets incident to vid. -1 if it has none.

◆ set_cell_quality()

void wmtk::components::topological_offset::TopoOffsetTetMesh::set_cell_quality ( const size_t  tid,
const double  q 
)
inlineoverridevirtual

◆ set_vertex_position()

void wmtk::components::topological_offset::TopoOffsetTetMesh::set_vertex_position ( const size_t  vid,
const Vector3d &  p 
)
inline

Place a vertex, keeping its exact and rounded coordinates in step.

The offset works in doubles throughout, so every vertex it places is rounded, but m_pos must still be filled: the shared split's exact-midpoint fallback reads it, and every quality and orientation test around an unrounded vertex reads its neighbours' m_pos.

◆ smooth_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::smooth_after ( const Tuple &  t)
overridevirtual

User specified modifications and desideratas for after smoothing a vertex.

Parameters
tTuple refering to a vertex
Returns
true if the preparation succeed

Reimplemented from wmtk::TetOptimizerMesh.

◆ smooth_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::smooth_before ( const Tuple &  t)
overridevirtual

User specified preparations and desideratas for smoothing a vertex.

Parameters
tTuple refering to a vertex Tuple
Returns
true if the preparation succeed

Reimplemented from wmtk::TetOptimizerMesh.

◆ smooth_group_to_convergence()

void wmtk::components::topological_offset::TopoOffsetTetMesh::smooth_group_to_convergence ( const char *  group_name)

The interleaved smoothing of one operation group under adaptive_smoothing: one pass at a time through local_operations({0,0,0,1}), each followed by smoothing_progress(), until the front has converged (max ratio <= 1) or stalled (max ratio fell by less than adaptive_smoothing_stall_rel) AND the background has settled (max step <= adaptive_smoothing_step_rel x its target edge), or adaptive_smoothing_max_passes.

◆ smoothing_containment_envelope()

std::shared_ptr< SampleEnvelope > wmtk::components::topological_offset::TopoOffsetTetMesh::smoothing_containment_envelope ( const size_t  vid) const
inlineoverridevirtual

... and it is not contained by one either, except in Phase A. Both families composed – not a choice between them; see containment_for().

Reimplemented from wmtk::TetOptimizerMesh.

◆ smoothing_energy_envelope()

std::shared_ptr< SampleEnvelope > wmtk::components::topological_offset::TopoOffsetTetMesh::smoothing_energy_envelope ( const size_t  vid) const
inlineoverridevirtual

The offset surface is the one tracked surface with no envelope, in either role.

The pull must be a real envelope, never a composite; so a junction vertex is pulled toward its most-violated member tube instead, one real envelope per attempt, while the containment intersection below enforces the full constraint. As in 2D.

Implements wmtk::TetOptimizerMesh.

◆ smoothing_extra_energy()

std::shared_ptr< polysolve::nonlinear::Problem > wmtk::components::topological_offset::TopoOffsetTetMesh::smoothing_extra_energy ( const size_t  vid) const
inlineoverridevirtual

Phase B's offset terms, handed to the shared smoother for a front vertex it is placing (null in Phase A and for a front vertex an input envelope also pins) – plus, under deform_others, the rest-shape AMIPS of the deformable cells in the vertex's ring.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_adjust_position()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_adjust_position ( size_t  ,
const std::vector< Tuple > &   
)
overridevirtual

Optional annotation-only adjustment of the midpoint. Ordinary optimization returns true without changing the shared TetWild position.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_after_cells()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_after_cells ( size_t  ,
size_t  ,
size_t  ,
const std::vector< Tuple > &   
)
overridevirtual

Restore application cell data on the children made by a split.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_after_vertex()

void wmtk::components::topological_offset::TopoOffsetTetMesh::split_after_vertex ( size_t  ,
bool   
)
overridevirtual

Application metadata not represented by the shared vertex attributes.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_before_cells()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_before_cells ( const Tuple &  edge,
const std::vector< Tuple > &  parents 
)
overridevirtual

Split policy that is the offset's own: which region tag the two child tets inherit, and which of the two tracked surfaces the new vertex joined. See EdgeSplittingTet.cpp.

The shared split places the new vertex, keeps quality and shared attributes, and checks envelope containment. These three hooks add what only the offset knows: which region tag each child tet inherits, and which tracked surfaces the new vertex joined.

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_edge_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_edge_after ( const Tuple &  t)
overridevirtual

This function computes the attributes for the added simplices. User specified modifications and desideratas for after an edge split.

Parameters
theedge Tuple to be split
Returns
true if the modification succeed

check inversion & rounding

update quality

containment: the new surface triangles must stay inside the envelope

update vertex attribute

update face attribute

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_edge_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_edge_before ( const Tuple &  t)
overridevirtual

User specified preparations and desideratas for an edge split before changing the connectivity.

Parameters
theedge Tuple to be split
Returns
true if the preparation succeed

save face track info

Reimplemented from wmtk::TetOptimizerMesh.

◆ split_edge_is_due()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_edge_is_due ( const Tuple &  e) const

The shared split pass's gate: TetOptimizerMesh::split_all_edges's is_weight_up_to_date without its staleness test.

◆ split_face_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_face_after ( const Tuple &  t)
overridevirtual

Compute the attributes for the added simplices.

User specified modifications and desideratas for after a face split

Parameters
tThe face tuple to be split.
Returns
true if the modification succeed

Reimplemented from wmtk::TetMesh.

◆ split_face_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_face_before ( const Tuple &  t)
overridevirtual

User specified preparations and desideratas for a face split before changing the connectivity.

Parameters
tThe face tuple to be split.
Returns
true if the preparation succeed.

Reimplemented from wmtk::TetMesh.

◆ split_off_longest()

static bool & wmtk::components::topological_offset::TopoOffsetTetMesh::split_off_longest ( )
inlinestatic

Whether the split running on this thread is off the longest edge of an incident tet. Set by split_edge_before(), counted by op_event() when that split commits.

◆ split_tet_after()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_tet_after ( const Tuple &  t)
overridevirtual

Compute the attributes for the added simplices.

User specified modifications and desideratas for after a tet split

Parameters
tThe tet tuple to be split.
Returns
true if the modification succeed

Reimplemented from wmtk::TetMesh.

◆ split_tet_before()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::split_tet_before ( const Tuple &  t)
overridevirtual

User specified preparations and desideratas for a tet split before changing the connectivity.

Parameters
tThe tet tuple to be split.
Returns
true if the preparation succeed.

Reimplemented from wmtk::TetMesh.

◆ stamp_rest_cell()

void wmtk::components::topological_offset::TopoOffsetTetMesh::stamp_rest_cell ( size_t  tid)

Stamp rest := the cell's current corner positions (oriented order). No-op for non-deformable cells.

◆ stencil_points_per_face()

int wmtk::components::topological_offset::TopoOffsetTetMesh::stencil_points_per_face ( ) const
inline

How many points for_each_face_sample() visits at the configured order: 3 at order 0, and (n+1)(n+2)/2 + n^2 with n = 2^(k-1) above it, i.e. 4, 10, 31, 109, ... Kept in step with for_each_face_sample() by the unit test stencil-order-point-counts.

◆ surface_envelope_for_face()

std::shared_ptr< SampleEnvelope > wmtk::components::topological_offset::TopoOffsetTetMesh::surface_envelope_for_face ( const std::array< size_t, 3 > &  vids) const
inlineoverridevirtual

Class-0 faces – every region boundary, the input complex and the domain wall included – carry a containment requirement; the offset surface does not, except in Phase A where m_offset_envelope holds it where the last smoothing pass left it.

The 3D twin of surface_envelope_for_edge(), keyed on the vertices because every caller is an operation asking about a triangle it is about to create. Null means "no containment requirement", which the base handles by skipping the check.

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_after_cells()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_after_cells ( const std::vector< size_t > &  ,
bool   
)
overridevirtual

Propagate application data to the cells made by a successful topological swap.

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_before_interior()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_before_interior ( const std::vector< size_t > &  tids)
overridevirtual

Which tag the tets a swap creates should carry, and the topology half of the surface-flip refusal (class match, mask match). The geometric half is the shared swap's containment check. See Optimize3d.cpp.

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_before_surface()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_before_surface ( const std::vector< size_t > &  tids,
size_t  a,
size_t  b,
size_t  c,
size_t  d 
)
overridevirtual

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_capture_tag()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_capture_tag ( const std::vector< size_t > &  tids)
private

INTERIOR swaps only: the ring must be homogeneous in tag and in construction label, and the single value of each is captured for swap_after_cells() to stamp on the new cells. A ring that is not homogeneous has a region boundary or the offset surface running through it, and an interior swap would move that boundary.

DO NOT call this on the surface path. A face is on the offset surface exactly when one incident cell is band and the other is not (cell_is_offset_band: label == 2), so the ring around a surface-flip edge ALWAYS spans two labels and this always refuses – which is what made every offset-surface flip impossible until 2026-09-17. The surface path uses swap_capture_surface_sides() instead.

◆ swap_edge_44_energy()

double wmtk::components::topological_offset::TopoOffsetTetMesh::swap_edge_44_energy ( const std::vector< std::array< size_t, 4 > > &  tets,
const int  op_case 
)
overridevirtual

Counting only: the scored cases of a 4-4 / 5-6 flip of the offset surface, for [flip funnel]. The energy returned is the base's.

TetMesh::swap_edge_44() and swap_edge_56() pick their retetrahedralization by seeding min_energy with the energy of DOING NOTHING (op_case 0) and taking a case only when it scores strictly lower, before any after-hook runs. That case search IS the quality half of the rule for these two swaps. op_case 0 is recorded (SwapSurfaceSides::case0_energy) so each scored case can be counted as inverted, not better, or better.

Until 2026-09-25 these overrides reported stop_energy for op_case 0, which turned the base's test into "the new cells are under stop_energy" for flips of the offset surface (the absolute bar; see swap_before_surface() for why it existed and why it went).

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_edge_56_energy()

double wmtk::components::topological_offset::TopoOffsetTetMesh::swap_edge_56_energy ( const std::vector< std::array< size_t, 4 > > &  tets,
const int  op_case 
)
overridevirtual

User specified energy to decide which of the 5 possible orientations should be chosen.

Accepts the last shown orientation if not overridden.

Parameters
tetsNew tets after performing a 5-6 swap.
op_caseThe operation case, where 0 are the tets before swap.
Returns
energy The swap giving the tets with the lowest energy are chosen.

Reimplemented from wmtk::TetOptimizerMesh.

◆ swap_quality_allowed()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::swap_quality_allowed ( const double  after,
const double  before,
const bool  is_surface_flip 
) const
inlineoverridevirtual

The quality half of the acceptance rule for every swap, a flip of the offset surface included: the cells a swap makes must be STRICTLY better than the cells it replaces – the base's rule, unchanged. The sag half is swap_before_surface(); its comment has the history of the absolute bar (new cells under stop_energy) that flips of the offset surface were judged on until 2026-09-25. Overridden only to count, for [flip funnel], the flips of the offset surface that reach it.

There is deliberately no PLACEMENT test: front_vertex_conv_ratio() is a function of the vertex's position alone, and a swap moves no vertex – so it cannot change.

Reimplemented from wmtk::TetOptimizerMesh.

◆ tet_flatness()

double wmtk::components::topological_offset::TopoOffsetTetMesh::tet_flatness ( size_t  tid) const

Scale-invariant flatness: 6 * volume / longest_edge^3.

~0.118 for a regular tet, -> 0 as the four vertices become coplanar, and independent of size. AMIPS saturates at the MAX_ENERGY sentinel while this keeps resolving. The 2D twin is face_flatness().

◆ vertex_boundary_mask()

uint64_t wmtk::components::topological_offset::TopoOffsetTetMesh::vertex_boundary_mask ( const size_t  vid) const
inline

The tag boundaries this vertex lies on – the raw mask gated on the vertex still being region geometry at all. The gate keeps the mask honest: the split's endpoint AND over-claims on chords through the interior, and the front is built by splitting exactly such edges.

◆ vertex_has_live_offset_face()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::vertex_has_live_offset_face ( size_t  vid) const

Whether ANY live offset-surface face is incident to vid. The same question offset_surface_faces_live_at() answers, without building the list: this one runs in the operation hooks, where the list would be allocated and thrown away.

◆ vertex_is_on_domain_boundary()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::vertex_is_on_domain_boundary ( const size_t  vid) const
inline

Identification only – no operation refuses the domain wall through these.

The wall is a tracked region boundary like every other one: init_surfaces_and_boundaries() tags its faces m_is_surface_fs, masks its vertices with ambient's bit and puts its faces in ambient's envelope, so refinement, coarsening, flips and smoothing are governed by the same containment, merge rules and link conditions that govern the input complex. As in 2D.

◆ vertex_is_on_region()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::vertex_is_on_region ( const size_t  vid) const
inline

Is this vertex on a region boundary – a tag boundary, or the domain wall. Derived, not stored, exactly as in 2D.

◆ vertex_is_on_surface()

bool wmtk::components::topological_offset::TopoOffsetTetMesh::vertex_is_on_surface ( const size_t  vid) const
overridevirtual

Is a vertex part of the substructure.

Parameters
vidVertex ID

Reimplemented from wmtk::TetOptimizerMesh.

◆ vertex_ring_measure()

double wmtk::components::topological_offset::TopoOffsetTetMesh::vertex_ring_measure ( const std::vector< std::array< size_t, 3 > > &  ring) const

front_measure "vertex_ring"'s VERTEX measure over a given ring of offset faces – energy_criterion()'s ring measure, on faces the caller supplies so the ops guard can measure a ring the mesh does not carry yet: over the faces with three front corners, sqrt(sum_f A_f r_f^2 / sum_f A_f), r_f = face_conv_ratio(), A_f = ring_face_area(). +inf when a face is unmeasurable or the areas sum to zero; -1 when no face has three front corners (no ring).

◆ warn_if_offset_reaches_domain_boundary()

void wmtk::components::topological_offset::TopoOffsetTetMesh::warn_if_offset_reaches_domain_boundary ( ) const

Warn if the offset band has grown into the domain boundary.

When target_distance exceeds the clearance between the input complex and the bounding box, construction runs out of room and the band's outer surface becomes the box itself; those vertices are pinned and the target distance is unreachable there.

◆ write_debug_pvd()

void wmtk::components::topological_offset::TopoOffsetTetMesh::write_debug_pvd ( ) const

DEBUG_output: rewrite <output>{_main,_off,_surf,_edge,_front}.pvd, a ParaView time series over the debug frames. Needed because ParaView only groups a file series when the index is immediately before the extension, which is false for every companion (<output>_NNNNN_off.vtu). Called after every frame, so a killed run still opens.

◆ write_optimization_debug_output()

void wmtk::components::topological_offset::TopoOffsetTetMesh::write_optimization_debug_output ( const std::string &  path)
inlineoverridevirtual

Put the optimization's frames on the run's single debug timeline (see write_debug_frame()), labelled "r<round><phase><pass>_<op>" / "r<round><phase>_end". Same scheme as 2D.

Implements wmtk::TetOptimizerMesh.

◆ write_phi_grid()

void wmtk::components::topological_offset::TopoOffsetTetMesh::write_phi_grid ( const std::string &  path,
int  n 
) const

output stuff Sample the potential on the plane through the box centre normal to its shortest extent and write it as <path>_phi.vtu, n x n samples. See phi_grid_resolution; 0 disables.

Member Data Documentation

◆ churn_counts

std::vector<std::array<int, 3> > wmtk::components::topological_offset::TopoOffsetTetMesh::churn_counts

{split-born vertices, recollapsed, recollapsed in the immediately following collapse pass} per turn, in step with op_counts. See VertexExtra::m_born_epoch.

◆ flip_trace_bar

std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::flip_trace_bar {0}

of those, the ones over the tube (given the bar)

◆ flip_trace_dec

std::array<std::atomic<long long>, 8> wmtk::components::topological_offset::TopoOffsetTetMesh::flip_trace_dec {}

Accepted flips bucketed by the size of the fall, before - after: >=1e-1, >=1e-2, >=1e-3, >=1e-4, >=1e-6, >=1e-9, >=1e-12, and everything below that.

◆ flip_trace_nonmono

std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::flip_trace_nonmono
Initial value:
{
0}

fall < 0 (a rise): MUST stay 0, the rule forbids it

◆ funnel_case_inverted

std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::funnel_case_inverted {0}
mutable

The scored CASES of those flips, by what the base's own energy said about them against the current cells (SwapSurfaceSides::case0_energy). An inverted case is one whose retetrahedralization inverts a cell – swap_edge_*_energy returns double::max() for that – which is a geometric refusal, not a quality one. Only a better case passes the base's energy < min_energy test, so case_better is what can still become a swap.

◆ funnel_cases

std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::funnel_cases {0}
mutable

of the 4-4 and 5-6 ones, those for which at least one case survived accept_case and was scored. offered(4-4 + 5-6) - this is exactly what flip_wrong_case threw away.

◆ funnel_offered

std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::funnel_offered {0}
mutable

[flip funnel]: of the flips of the offset surface that passed the sag rule, how many survive each later stage. Reset per turn and reported next to [swap reject].

[swap reject] counts every refusal of every surface flip, most of which SHOULD be refused. This follows only the flips that passed the sag rule of swap_before_surface() – the pair's worst face measure not raised – so a drop here is the quality half at work.

Reading it. passed the sag rule is set in swap_before_surface(), which is the app's first sight of a candidate; anything the base turned down earlier (valence, bbox, connectivity) never reaches it and is in [swap reject] instead. For a 4-4 or 5-6, what does not reach the quality test is lost in the base's case search: no retetrahedralization that makes the (c,d) diagonal was found, or none scored strictly below the current cells (the cases split). quality - quality_ok is a 3-2 refused for not being strictly better than the cells it replaces. quality_ok - committed is swap_after_cells() refusing on the side/label capture. What the envelope check then refuses is past this hook and shows as after_envelope in [swap reject].

◆ INPUT_SURFACE_CLASS

constexpr int wmtk::components::topological_offset::TopoOffsetTetMesh::INPUT_SURFACE_CLASS = 0
staticconstexpr

SurfaceTagAttributes::m_surface_class: which of the two tracked surfaces a face belongs to. Same scheme as 2D.

OFFSET is the surface the optimization places at target_distance. Everything else – the input complex, another body's boundary, the domain wall – keeps the primary class 0 and is envelope-checked by the shared operations exactly as in tetwild and simwild. Class 0 is not split further – the boundary mask says which tubes hold a simplex, per tag.

◆ iter_cnt_collapse_guard_reject

std::atomic<int> wmtk::components::topological_offset::TopoOffsetTetMesh::iter_cnt_collapse_guard_reject {0}

The ops divergence guard: operations refused for raising the local sag of the offset surface.

◆ iter_cnt_split_born

std::atomic<int> wmtk::components::topological_offset::TopoOffsetTetMesh::iter_cnt_split_born {0}

Churn: split-born vertices that a collapse later removed, and the subset removed in the same pass-pair that created them.

◆ kFlipTraceEvery

constexpr long long wmtk::components::topological_offset::TopoOffsetTetMesh::kFlipTraceEvery = 20000
staticconstexpr

[flip trace]: is the swap pass walking the offset surface's sag down monotonically, and in steps of what size? The per-turn lines cannot answer that, because a pass that does not finish never reaches the end of its turn – so this prints from INSIDE the pass, every kFlipTraceEvery accepted flips. Live only where the guard measured a pair, i.e. only under the ops divergence guard, and only for flips of the offset surface.

Counted at swap_after_cells(), which is past the sag refusal and past the quality gate but still before the envelope check, so it overcounts by the after_envelope refusals – tens per turn against thousands of flips.

◆ m_ab_round

int wmtk::components::topological_offset::TopoOffsetTetMesh::m_ab_round = 0

The turn the run is in, 1-based; 0 before the loop starts. Read only by write_optimization_debug_output(), to tag each frame with the turn it belongs to.

◆ m_collapse_edge_link

wmtk::threading::enumerable_thread_specific<std::vector<size_t> > wmtk::components::topological_offset::TopoOffsetTetMesh::m_collapse_edge_link
mutable

The link of the collapsed edge, captured in collapse_before_vertex().

Which vertices a collapse can move off the offset surface, exactly: the faces that DIE are the ones carrying both endpoints, (v1, v2, w) for w in the link, so only v2 and those w can lose their last surface face. A face (v1, a, b) with neither corner on the edge does not die – it is relabelled onto v2 – so a and b keep it and are unaffected. Nothing but v2 can gain, since faces only ever move from v1 to v2.

Captured before the collapse because the edge is gone by collapse_after_vertex(), which is where the refresh runs.

◆ m_collapse_survivor_sizing

wmtk::threading::enumerable_thread_specific<double> wmtk::components::topological_offset::TopoOffsetTetMesh::m_collapse_survivor_sizing
mutable

The collapse survivor's own sizing scalar, recorded in collapse_edge_before() and put back in collapse_edge_after() when sizing_collapse_min is false; see that key.

◆ m_complex_tag

constexpr int64_t wmtk::components::topological_offset::TopoOffsetTetMesh::m_complex_tag = -3
staticconstexpr

pseudo-tag: the input complex boundary

◆ m_converged

bool wmtk::components::topological_offset::TopoOffsetTetMesh::m_converged = false

The run's verdict: the front resolved (EnergyCriterion::converged(): every offset face's measure within the bar, nothing unmeasurable) AND the final quality under stop_energy. Read by the report and by throw_on_nonconvergence.

◆ m_debug_frame_labels

std::vector<std::string> wmtk::components::topological_offset::TopoOffsetTetMesh::m_debug_frame_labels
mutable

DEBUG_output: the label of each debug frame, indexed by its sequence number, and, per companion suffix, the frame indices that actually produced one. Both exist only to write the ParaView collections – see write_debug_pvd(). Same in 2D.

◆ m_debug_pass

int wmtk::components::topological_offset::TopoOffsetTetMesh::m_debug_pass = 0
mutable

Pass index within the current phase, and the (round, phase) it belongs to – when those change the index restarts. All three exist only to name frames.

◆ m_energy_verdict

std::optional<EnergyCriterion> wmtk::components::topological_offset::TopoOffsetTetMesh::m_energy_verdict

The energy criterion as measured when the loop converged; the final Phase A runs after it and the verdict must not be re-measured on that mesh.

◆ m_front_gradient_reference

double wmtk::components::topological_offset::TopoOffsetTetMesh::m_front_gradient_reference = 0.

Its value on the band as constructed, measured once before turn 1: the reference the gradient_norm_rel criterion is a fraction of.

◆ m_front_gradient_worst_vid

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::m_front_gradient_worst_vid
mutable
Initial value:
=
static_cast<size_t>(-1)

argmax of phase_b_front_gradient_linf()

◆ m_input_complex_bvh

std::shared_ptr<SimplicialComplexBVH> wmtk::components::topological_offset::TopoOffsetTetMesh::m_input_complex_bvh

The input complex as loaded. Built once, never rebuilt.

It answers the Euclidean distance to the input, a diagnostic rather than the definition of the offset – see m_offset_potential. init_input_complex_bvh() has one call site, before execute_offset() runs, so this holds the original geometry however the elements representing the complex are later remeshed. Rebuilding from the live mesh would redefine the offset distance in terms of a surface the optimizer had just moved.

Containment is not its job – the per-tag region envelopes (m_tag_envelopes) hold the complex in place.

◆ m_input_complex_envelope

std::shared_ptr<SampleEnvelope> wmtk::components::topological_offset::TopoOffsetTetMesh::m_input_complex_envelope

The exact-kind envelope of the input complex, built only for offset_field "euclidean". Null otherwise.

Not a containment envelope and never used as one: no operation tests against it. It exists because nearest_point_feature() – the foot point plus the feature kind the exact distance derivatives case on – is only answered by the exact path. Built from the same extraction as m_input_complex_bvh, so it describes the same geometry.

◆ m_isect_cache

std::map<uint64_t, std::shared_ptr<SampleEnvelope> > wmtk::components::topological_offset::TopoOffsetTetMesh::m_isect_cache
mutable

Memoized IntersectionEnvelope per multi-bit mask. Lazily built under the mutex because the queries that need them run concurrently under kPartition.

◆ m_marching_root_splits

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::m_marching_root_splits = 0

marching_tets() tallies for the construction log: edges placed on the level set / at the midpoint because the trace left the edge, and the trace steps (total, max). Reset at the start of marching_tets().

◆ m_n_regions

int wmtk::components::topological_offset::TopoOffsetTetMesh::m_n_regions = 0

One field per connected piece of the input complex, and which one each band vertex is placed on. See TopoOffsetTriMesh::m_region_potentials for the full argument.

m_offset_potential is built over the whole selected complex; where two pieces are close the union field has no level set across the gap. A band grown from one piece is placed on that piece's field alone. Pieces are the connected components of the captured complex under vertex connectivity, numbered once in init_input_complex_bvh(); assign_band_regions() maps the band's cells and vertices to them by a flood fill seeded from complex vertices. connected pieces of the input complex; one field each

◆ m_newton_front

optimization::NewtonCounters wmtk::components::topological_offset::TopoOffsetTetMesh::m_newton_front

How the solves this class makes itself ended, per smoothing pass, beside the base's m_newton (the background, through TetOptimizerMesh::smooth_after()). Front: every front placement in the phases that place it – the 1-D solve along the field normal and the 3-D solve it falls back to. Plastic: the rest-shape solve of smooth_plastic_vertex(). Logged and reset by log_smoothing_pass_accounting().

◆ m_offset_face_invalid_tuple

std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::m_offset_face_invalid_tuple {0}
mutable

face_is_offset_surface_live() calls handed an invalid Tuple (m_global_tid == size_t(-1)). Defence in depth behind the two walks above: with both of them checking their lookups this should stay 0, and a future caller that forgets gets false instead of a wild read.

◆ m_offset_face_lookup_misses

std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::m_offset_face_lookup_misses {0}
mutable

Faces that vertex_has_live_offset_face() / offset_surface_faces_live_at() asked for and the connectivity did not have.

Both walk a vertex's one-ring of tets and then step across each face to the tet on the other side, so they read two and three hops out from the seed. The collapse and swap passes guarantee only {v1, v2} u N(v1) u N(v2) – see "Ring lockers -- NOT balls" in TetMesh.h – so at num_threads > 0 a neighbouring thread can be shrinking a vertex fan these walks are reading, and the face lookup misses. A miss is taken as "not a live offset face", which is what TetMesh.h's try_tuple_from_face doc calls the legitimate answer.

Counted because a miss means the m_is_on_offset just written was derived from a stale read and may be wrong. Zero is the expected value. Non-zero says the walks are racing the pass, and the remedy is to widen the collapse pass's lock (collapse_all_edges_impl's exact_ball_lock), which is shared code and not an offsets-side change.

History: before 2026-09-18 neither walk checked for a miss. The asserting tuple_from_face returns a default Tuple under NDEBUG, whose m_global_tid is size_t(-1), and switch_tetrahedron() indexed m_tet_connectivity with it – one element below the vector's base. That was the SIGSEGV on the cube at target_distance_rel 1e-3.

◆ m_offset_isect_cache

std::map<uint64_t, std::shared_ptr<SampleEnvelope> > wmtk::components::topological_offset::TopoOffsetTetMesh::m_offset_isect_cache
mutable

Memoized "region tubes AND the offset envelope", keyed by the region mask.

Separate from m_isect_cache because the members differ in lifetime: the tag envelopes live for the whole run, m_offset_envelope is rebuilt after every smoothing pass. rebuild_offset_envelope() clears this and must keep doing so. Guarded by m_isect_mutex.

◆ m_offset_potential

std::shared_ptr<OffsetPotential3D> wmtk::components::topological_offset::TopoOffsetTetMesh::m_offset_potential

The smooth offset potential, and with it the definition of the offset itself.

The offset surface is the level set Phi = c. Built from the same extraction as m_input_complex_bvh, so the two describe the same geometry and the same never-rebuilt rule applies. See OffsetPotential for what Phi is. shared_ptr because OffsetEnergy3D holds one per smoothing call.

◆ m_phi_V

MatrixXd wmtk::components::topological_offset::TopoOffsetTetMesh::m_phi_V

The input complex as Phi's primitives: the BOUNDARY triangles of the label-1 tet region plus the complex's isolated triangles, every edge of those triangles plus the complex's wires, and its isolated points. Filled by init_input_complex_bvh().

◆ m_placement_env_entry_outside

std::atomic<int> wmtk::components::topological_offset::TopoOffsetTetMesh::m_placement_env_entry_outside {0}
mutable

How many front placements found the vertex already outside its own envelope on entry. The invariant is 0. A run total.

◆ m_placement_projected

std::atomic<int> wmtk::components::topological_offset::TopoOffsetTetMesh::m_placement_projected {0}
mutable

How many front placements had their accepted step projected back into the vertex's region tubes. A run total.

◆ m_placement_tangential

std::atomic<int> wmtk::components::topological_offset::TopoOffsetTetMesh::m_placement_tangential {0}
mutable

How many front placements were solved tangentially – along the vertex's own region boundary rather than along the field normal. A run total.

◆ m_plastic_active

bool wmtk::components::topological_offset::TopoOffsetTetMesh::m_plastic_active = false

set in optimize_offset() when deform_others

Plastic medium: under deform_others every background cell – ambient and the other objects alike – is plastic, its rest shape re-stamped before every operation group, so smoothing resists only the increment since the group started and the medium flows instead of behaving as an elastic solid glued to the walls. The band (label 2) and the complex (label 1) are not plastic; element quality in the medium is the operation passes' job.

◆ m_quality_converged

bool wmtk::components::topological_offset::TopoOffsetTetMesh::m_quality_converged = true

The finishing-pass half of the verdict: max AMIPS < stop_energy once the front is resolved, after the final pass when one ran. True when no pass was needed; false when the pass ended still over. m_quality_max_amips is the value it was judged on.

◆ m_region_bvhs

std::vector<std::shared_ptr<SimplicialComplexBVH> > wmtk::components::topological_offset::TopoOffsetTetMesh::m_region_bvhs

One BVH per piece, over that piece's primitives alone: what assign_band_regions() reads a seed vertex's piece off (nearest piece), and the euclidean per-piece field's engine. 2D answers the same question through its BVH's feature ids, which the 3D BVH has none of.

◆ m_region_potentials

std::vector<std::shared_ptr<OffsetPotential3D> > wmtk::components::topological_offset::TopoOffsetTetMesh::m_region_potentials

one per piece

◆ m_released_envelope

std::shared_ptr<SampleEnvelope> wmtk::components::topological_offset::TopoOffsetTetMesh::m_released_envelope
mutable

The released boundaries' ops-only tube: a SampleEnvelope around the current deformed boundaries, consulted only by surface_envelope_for_face(). Rebuilt lazily by released_envelope() when m_released_tube_dirty says a smoothing accept may have moved the boundary.

◆ m_sheet_tag

int64_t wmtk::components::topological_offset::TopoOffsetTetMesh::m_sheet_tag = -1

Tag id of the input's envelope surface group (the .msh triangle elements), or -1. An open sheet has no tet set whose boundary it is, so it is selectable only through this tag: offset_selection naming it makes the sheet the complex and the band grows on both of its sides. The 2D twin is m_curve_tag.

◆ m_source_tags

std::set<int64_t> wmtk::components::topological_offset::TopoOffsetTetMesh::m_source_tags

The source tags (offset_selection's tags_involved), stored at release so the ops-only tube's face classification applies the same never-freed rule the release did.

◆ m_split_order_waits

std::atomic<long> wmtk::components::topological_offset::TopoOffsetTetMesh::m_split_order_waits {0}

Longest-edge order in the optimization split (see split_edge_before()), counted per turn: splits that waited for a strictly longer edge of an incident tet that was over the split gate, and committed splits whose edge was not the longest edge of every incident tet.

◆ m_stuck_prev_cells

std::set<std::tuple<long, long, long> > wmtk::components::topological_offset::TopoOffsetTetMesh::m_stuck_prev_cells

Quantised centroids of the MAX_ENERGY tets at the previous stuck-refine, for the overlap line. Diagnostic only.

◆ m_swap_sides

wmtk::threading::enumerable_thread_specific<SwapSurfaceSides> wmtk::components::topological_offset::TopoOffsetTetMesh::m_swap_sides
mutableprivate

mutable: swap_quality_allowed() is a const hook and reads worthwhile; .local() is not const-callable.

◆ m_tag_bit

std::map<int64_t, int> wmtk::components::topological_offset::TopoOffsetTetMesh::m_tag_bit

Input tag id -> bit position in VertexExtra::m_boundary_mask. Assigned in init_from_image() once the tag maps are complete; at most 64 input tags.

◆ m_tag_envelopes

std::map<int64_t, std::shared_ptr<SampleEnvelope> > wmtk::components::topological_offset::TopoOffsetTetMesh::m_tag_envelopes

One containment envelope per input tag, ambient included. Both phases.

E_t is a tube of half-width m_envelope_eps around region t's boundary faces as the input mesh carried them, built in init_surfaces_and_boundaries() before offset construction: the band's tags replace a tet's own, so an envelope built later would be a tube around a surface truncated at the band. A simplex on several boundaries is held by the intersection of its tags' tubes (envelope_for_mask()), which pins junction curves and points.

m_envelope (the base's pointer) survives as a UnionEnvelope over these members, purely so the shared engine's direct uses of it keep union semantics.

◆ m_worst_dist_vid

size_t wmtk::components::topological_offset::TopoOffsetTetMesh::m_worst_dist_vid = static_cast<size_t>(-1)
mutable

The vertex compute_distance_deviation() last found the max at, and a dump of everything that could be stopping it from moving. Diagnostic only.

◆ optimization_metrics

std::vector<std::array<double, 8> > wmtk::components::topological_offset::TopoOffsetTetMesh::optimization_metrics

{max_dist_err, avg_dist_err, max_phi_residual, avg_phi_residual, max_grad, avg_grad, max_grad_at_vertex, max_grad_in_face}. One entry for the whole run, as in 2D.


The documentation for this class was generated from the following files: