|
Wildmeshing Toolkit
|
The offset's tet mesh, on the shared 3D optimizer. More...
#include <TopoOffsetTetMesh.h>
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 ¶ms, 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 > > ¢er_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. | |
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.
|
strong |
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.
|
strong |
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).
|
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.
|
inlineprivate |
determine if any tag from tag1 is also present in tag2.
| 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.
| 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+
|
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.
| 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.
|
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.
| 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.
|
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.
| 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.
| 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.
| 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.
|
inlineoverridevirtual |
Implements wmtk::TetOptimizerMesh.
| 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.
|
overridevirtual |
Reimplemented from wmtk::TetOptimizerMesh.
|
overridevirtual |
Reimplemented from wmtk::TetOptimizerMesh.
|
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.
|
overridevirtual |
The coarsening bar, the sizing restore and the rest re-stamp, after the base accepted.
Reimplemented from wmtk::TetOptimizerMesh.
|
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.
|
inlineoverridevirtual |
Reimplemented from wmtk::TetOptimizerMesh.
|
overridevirtual |
Instrumentation only: which operation manufactures the MAX_ENERGY needles.
Reimplemented from wmtk::TetOptimizerMesh.
| 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().
| 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.
| 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.
| 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().
| 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.
| 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.
|
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.
| 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.
| 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.
| 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).
|
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.
| 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().
|
overridevirtual |
Is a face part of the substructure.
| fid | Face ID |
Reimplemented from wmtk::TetOptimizerMesh.
|
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.
| 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.
|
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().
| 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.
| 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().
|
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.
| 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.
| 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.
| 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.
| 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.
| 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.
|
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.
| vid | Vertex ID |
Reimplemented from wmtk::TetOptimizerMesh.
| 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.
| 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.
| TopoOffsetTetMesh::GradientSplit wmtk::components::topological_offset::TopoOffsetTetMesh::gradient_split | ( | bool | include_face_samples = true | ) | const |
| include_face_samples | false skips the face-interior half (the expensive one). |
| 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
| V | #V by 3 vertex matrix |
| T | #T by 4 tet matrix |
| T_tags | #T by #tags tag matrix |
| V_env | V_env by 3 EnvelopeSurface vertices |
| F_env | F_env by 3 EnvelopeSurface faces |
| 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.
|
overridevirtual |
Reimplemented from wmtk::TetOptimizerMesh.
| 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.
|
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.
| 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().
| 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().
| 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.
|
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.
| 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().
| bool wmtk::components::topological_offset::TopoOffsetTetMesh::marching_split_edge_after | ( | const Tuple & | t | ) |
check inversion & rounding
| 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).
| 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.
| 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().
| 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().
|
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.
| 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.
|
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.
| 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().
| 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.
| 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.
|
overridevirtual |
Reimplemented from wmtk::TetOptimizerMesh.
| 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.
| 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.
|
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.
|
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.
|
inlineoverridevirtual |
stop_energy outside Phase B, 1.0 in it – in the same units as the line above.
Reimplemented from wmtk::TetOptimizerMesh.
| 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.
| 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.
| 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.
|
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.
|
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.
| 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.
| 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.
| 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.
|
overridevirtual |
TetWild's stall-driven sizing refinement, verbatim; Phase A only. See the 2D twin.
Implements wmtk::TetOptimizerMesh.
| 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.
| 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.
| 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.
| 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.
| 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.
| 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.
| 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.
|
inlineoverridevirtual |
Implements wmtk::TetOptimizerMesh.
|
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.
|
overridevirtual |
User specified modifications and desideratas for after smoothing a vertex.
| t | Tuple refering to a vertex |
Reimplemented from wmtk::TetOptimizerMesh.
|
overridevirtual |
User specified preparations and desideratas for smoothing a vertex.
| t | Tuple refering to a vertex Tuple |
Reimplemented from wmtk::TetOptimizerMesh.
| 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.
|
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.
|
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.
|
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.
|
overridevirtual |
Optional annotation-only adjustment of the midpoint. Ordinary optimization returns true without changing the shared TetWild position.
Reimplemented from wmtk::TetOptimizerMesh.
|
overridevirtual |
Restore application cell data on the children made by a split.
Reimplemented from wmtk::TetOptimizerMesh.
|
overridevirtual |
Application metadata not represented by the shared vertex attributes.
Reimplemented from wmtk::TetOptimizerMesh.
|
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.
|
overridevirtual |
This function computes the attributes for the added simplices. User specified modifications and desideratas for after an edge split.
| the | edge Tuple to be split |
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.
|
overridevirtual |
User specified preparations and desideratas for an edge split before changing the connectivity.
| the | edge Tuple to be split |
save face track info
Reimplemented from wmtk::TetOptimizerMesh.
| 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.
|
overridevirtual |
Compute the attributes for the added simplices.
User specified modifications and desideratas for after a face split
| t | The face tuple to be split. |
Reimplemented from wmtk::TetMesh.
|
overridevirtual |
User specified preparations and desideratas for a face split before changing the connectivity.
| t | The face tuple to be split. |
Reimplemented from wmtk::TetMesh.
|
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.
|
overridevirtual |
Compute the attributes for the added simplices.
User specified modifications and desideratas for after a tet split
| t | The tet tuple to be split. |
Reimplemented from wmtk::TetMesh.
|
overridevirtual |
User specified preparations and desideratas for a tet split before changing the connectivity.
| t | The tet tuple to be split. |
Reimplemented from wmtk::TetMesh.
| 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.
|
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.
|
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.
|
overridevirtual |
Propagate application data to the cells made by a successful topological swap.
Reimplemented from wmtk::TetOptimizerMesh.
|
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.
|
overridevirtual |
Reimplemented from wmtk::TetOptimizerMesh.
|
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.
|
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.
|
overridevirtual |
User specified energy to decide which of the 5 possible orientations should be chosen.
Accepts the last shown orientation if not overridden.
| tets | New tets after performing a 5-6 swap. |
| op_case | The operation case, where 0 are the tets before swap. |
Reimplemented from wmtk::TetOptimizerMesh.
|
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.
| 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().
|
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.
| 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.
|
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.
|
inline |
Is this vertex on a region boundary – a tag boundary, or the domain wall. Derived, not stored, exactly as in 2D.
|
overridevirtual |
Is a vertex part of the substructure.
| vid | Vertex ID |
Reimplemented from wmtk::TetOptimizerMesh.
| 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).
| 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.
| 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.
|
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.
| 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.
| 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.
| std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::flip_trace_bar {0} |
of those, the ones over the tube (given the bar)
| 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.
| std::atomic<long long> wmtk::components::topological_offset::TopoOffsetTetMesh::flip_trace_nonmono |
fall < 0 (a rise): MUST stay 0, the rule forbids it
|
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.
|
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.
|
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].
|
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.
| 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.
| 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.
|
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.
| 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.
|
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.
|
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.
|
staticconstexpr |
pseudo-tag: the input complex boundary
| 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.
|
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.
|
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.
| 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.
| 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.
|
mutable |
argmax of phase_b_front_gradient_linf()
| 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.
| 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.
|
mutable |
Memoized IntersectionEnvelope per multi-bit mask. Lazily built under the mutex because the queries that need them run concurrently under kPartition.
| 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().
| 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
| 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().
|
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.
|
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.
|
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.
| 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.
| 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().
|
mutable |
How many front placements found the vertex already outside its own envelope on entry. The invariant is 0. A run total.
|
mutable |
How many front placements had their accepted step projected back into the vertex's region tubes. A run total.
|
mutable |
How many front placements were solved tangentially – along the vertex's own region boundary rather than along the field normal. A run total.
| 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.
| 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.
| 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.
| std::vector<std::shared_ptr<OffsetPotential3D> > wmtk::components::topological_offset::TopoOffsetTetMesh::m_region_potentials |
one per piece
|
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.
| 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.
| 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.
| 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.
| 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.
|
mutableprivate |
mutable: swap_quality_allowed() is a const hook and reads worthwhile; .local() is not const-callable.
| 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.
| 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.
|
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.
| 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.