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

The band-volume integral of one cell, in closed form: More...

#include <ExactBandIntegral.hpp>

Classes

class  FaceParts
 One face's labelled parts, kept by the caller between front_face() calls on that face, as Partition keeps a cell's partition: the parts are a function of f's 9 coordinates, in their order, and of the input alone (not of delta or kv). A call whose f equals, bit for bit, the f they were made for (by this integral) reads them; any other call makes them anew into it. Why: the smoother asks for the value at x and then for the derivatives at the same x, each labelling every boundary face through x. More...
 
struct  FaceWork
 
struct  Feature
 
struct  FFBox
 
struct  Local
 
struct  MaxInfo
 What max_distance() found besides the max. More...
 
struct  Node
 
class  Partition
 One cell's partition, kept by the caller between value() and value_grad_hess() of that cell: each partitions t (partition(), the candidates and the convex pieces) before integrating, and a partition is a function of t's 12 coordinates, in their order, and of the input alone. Given a Partition, a call whose t equals, bit for bit, the t the Partition was made for (by this integral) reads it; any other call partitions t into it. The value is therefore the one the call would compute without it. More...
 
class  QuietCurvedBisector
 While one is alive on a thread, a curved bisector crossing a piece of a face (front_face(), front_face_derivs()) throws without being logged first; every other error is logged as before. "exact_swept"'s search model catches that throw and takes the ring cells' derivatives at that x instead (BandVolumeEnergy3D::set_swept()): there it is an expected outcome, not an error, and each throw would otherwise log a line with the face in hex floats. More...
 
struct  Stats
 
struct  TriWork
 
struct  ValueSlot
 
struct  Work
 

Public Member Functions

 ExactBandIntegral (const Eigen::MatrixXd &V, const Eigen::MatrixXi &F)
 
 ExactBandIntegral (const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const std::vector< int8_t > &face_side, int sigma, size_t value_slots=0, std::shared_ptr< const wmtk::Envelope > envelope=nullptr)
 
double value (const std::array< Eigen::Vector3d, 4 > &t, double delta, Stats *stats=nullptr) const
 J(t) = int_t (d - delta) dV for the cell with corners t (either orientation), restricted to the offset side when constructed with one (class doc); 0 for a flat cell (|6 vol| <= 64 eps L^3, L its longest edge). With stats, adds to it.
 
double value (const std::array< Eigen::Vector3d, 4 > &t, double delta, Partition &keep) const
 value(t, delta), t's partition read from or written to keep (Partition).
 
void reserve_values (size_t slots) const
 
double value_grad_hess (const std::array< Eigen::Vector3d, 4 > &t, int kv, double delta, Eigen::Vector3d &grad, Eigen::Matrix3d &hess, Stats *stats=nullptr) const
 J and its exact gradient and Hessian with respect to corner kv of t, the other three fixed (exact_mesh.value_grad_hess): Reynolds' transport theorem on each smooth piece, a boundary integral over the three faces of t through x = t[kv], plus, on the Hessian, the terms of piece edges sliding over those faces ("cut edges"; they cancel in pairs between exact pieces and remain on rule-(a) pieces). J here sums the same pieces split into smooth parts, so it equals value() to rounding.
 
double value_grad_hess (const std::array< Eigen::Vector3d, 4 > &t, int kv, double delta, Eigen::Vector3d &grad, Eigen::Matrix3d &hess, Partition &keep) const
 value_grad_hess(), t's partition read from or written to keep (Partition).
 
void grad_hess (const std::array< Eigen::Vector3d, 4 > &t, int kv, double delta, Eigen::Vector3d &grad, Eigen::Matrix3d &hess, Partition &keep) const
 value_grad_hess()'s gradient and Hessian alone, t's partition read from or written to keep: J's own integration over the elementary pieces is skipped (the smoother reads the value from value() and only the derivatives from here – BandVolumeEnergy3D::eval()). The elementary pieces themselves are read from keep when a value() call with keep captured them for this t (bit for bit) and delta, else built as value_grad_hess() builds them; grad and hess equal value_grad_hess()'s bit for bit either way (exact-band-grad-hess-cache).
 
double max_distance (const std::array< Eigen::Vector3d, 3 > &f, MaxInfo *info=nullptr) const
 max over the triangle f of d (exact_mesh.max_on_triangle), the settle loop's max test. f is cut by the candidates' local regions as a cell is (the same search, region tests, splits, tolerances and scale rule; f a planar convex ring in place of a polytope), and d is convex wherever one member's distance is d, so on each piece the max is at a vertex of the piece:
 
double front_face (const std::array< Eigen::Vector3d, 3 > &f, double delta, FaceParts *keep=nullptr) const
 front_face(): int over the triangle f of G.n dA, n = (f1 - f0) x (f2 - f0) / |.| (f ordered with the normal pointing out of the band). front_face_derivs(): for the motion of corner kv (the others fixed), the gradient and the one-vertex Hessian of E's dependence through f: grad = n int_f chi (d - delta) phi dA, hess = n (x) int_f chi phi^2 grad d dA + (int_f chi (d - delta) phi dA / |N|) dN/dx
 
void front_face_derivs (const std::array< Eigen::Vector3d, 3 > &f, double delta, int kv, Eigen::Vector3d &grad, Eigen::Matrix3d &hess, FaceParts *keep=nullptr) const
 
double bisector_jump (const std::array< Eigen::Vector3d, 4 > &t, double delta, Partition *keep=nullptr) const
 D_t = int_t (d - delta) dV - oint_dt G.n dA of the cell t (either orientation): 0 exactly when one feature labels every part of t on the offset side (one field); otherwise the flux of each labelled part's field through its faces not on dt, outward from the part, a face on one of the label's own region planes skipped (the field is tangent to it). The faces between two parts of one label cancel, so the sum is the jumps of G.n where the label changes: on the bisectors, and on region planes that coincide with one (MEASURED, Python, cube_out tet 2234: the prism plane between two coplanar triangles of a cube face is the bisector of the two perpendicular faces at the cube edge it contains) or nearly so (see the .cpp). t's partition read from or written to keep when given (Partition). Throws on a curved bisector, or as value() if the pieces do not tile t.
 
void prepare_front_flux (double delta)
 Builds, from the input alone, where bisectors can be: for every pair of features g, h the polytope L_g cap L_h cap box_g(R) cap box_h(R) (and, with a side, cap both features' offset sides), R = reach = 2 delta, kept where it has volume. A bisector point y of g and h with d(y) <= R lies in it: both are nearest at y, so y is in both regions, on the offset side of both planes, and within d_g(y) = d(y) of a point of g (fact (ii) of the class doc), so in g's box grown by R. Called once, before the integral is shared.
 
double front_flux_reach () const
 prepare_front_flux()'s R (0 before it), and the number of polytopes it kept.
 
size_t front_flux_polytopes () const
 
bool front_flux_flag (const std::array< Eigen::Vector3d, 4 > &t) const
 Whether the cell t can meet a bisector at points with d <= front_flux_reach(): t's box meets a kept polytope's box and no face plane of that polytope has all four corners strictly outside it (beyond rounding). Conservative: a cell flagged without a bisector gets D_t = 0 up to rounding (exactly 0 when one feature labels all of it). Says nothing about points with d > reach: the caller flags a cell whose bound on d (distance_bound()) exceeds the reach itself (BandVolumeEnergy3D).
 
bool front_flux_flag (const Eigen::Vector3d *t, int n) const
 
double distance (const Eigen::Vector3d &x) const
 d(x), the distance to the input: min over the triangles of the point-triangle distance.
 
double distance_bound (const std::array< Eigen::Vector3d, 4 > &t) const
 
double distance_bound (const Eigen::Vector3d *t, const int n) const
 The same bound for the n points t; a subset's bound is never larger.
 
size_t num_faces () const
 

Private Member Functions

void localize (const Eigen::Vector3d *t, int n, Local &w, Stats *stats) const
 
bool partition (const std::array< Eigen::Vector3d, 4 > &t, Work &w, Stats *stats) const
 
const Work * cell_partition (const std::array< Eigen::Vector3d, 4 > &t, Stats *stats, Work *own, Partition *keep) const
 
double evaluate (const std::array< Eigen::Vector3d, 4 > &t, double delta, Stats *stats, Partition *keep) const
 value() without the value table.
 
double value_tabled (const std::array< Eigen::Vector3d, 4 > &t, double delta, Partition *keep) const
 value(t, delta, stats, keep) through the value table (value()).
 
double value_grad_hess_impl (const std::array< Eigen::Vector3d, 4 > &t, int kv, double delta, Eigen::Vector3d &grad, Eigen::Matrix3d &hess, Stats *stats, Partition *keep, bool want_value) const
 
void tri_partition (const std::array< Eigen::Vector3d, 3 > &f, TriWork &w) const
 _tri_partition: the same for the face f, its pieces planar rings.
 
double upper_bound (const Eigen::Vector3d *t, int n) const
 U: min over all triangles of max over the n points t of d_P.
 
void check_cell_pieces (const std::array< Eigen::Vector3d, 4 > &t, double delta, const Work &w, double vol_sum, double empty_vol) const
 
void check_face_pieces (const std::array< Eigen::Vector3d, 3 > &f, const TriWork &w, const char *who) const
 
void label_face (const std::array< Eigen::Vector3d, 3 > &f, FaceWork &fw) const
 
const FaceWork & face_parts (const std::array< Eigen::Vector3d, 3 > &f, FaceParts *keep) const
 f's labelled parts, from keep when it holds f's, else made (into keep, or a scratch).
 
int build_ff_node (int begin, int end)
 
void candidates (const Eigen::Vector3d &lo, const Eigen::Vector3d &hi, double r, std::vector< int > &out) const
 Feature indices whose box is within r of [lo, hi], ascending.
 

Private Attributes

std::vector< Feature > m_feat
 
std::vector< std::pair< Eigen::Vector3d, Eigen::Vector3d > > m_hs
 
int m_nF = 0
 
int m_nE = 0
 
std::vector< Eigen::Vector3d > m_A
 
std::vector< Eigen::Vector3d > m_B
 
std::vector< Eigen::Vector3d > m_C
 triangle corners, for d_P
 
std::vector< std::array< int, 6 > > m_face_feats
 
int m_sigma = 0
 
std::vector< char > m_side_has
 
std::vector< Eigen::Vector3d > m_side_n
 
std::vector< Eigen::Vector3d > m_side_q
 
std::shared_ptr< const wmtk::Envelope > m_env
 
double m_pad = 0.
 
uint64_t m_id = 0
 
std::vector< ValueSlot > m_values
 
std::unique_ptr< std::mutex[]> m_value_locks
 
std::vector< FFBox > m_ff_boxes
 
std::vector< Node > m_ff_nodes
 
std::vector< int > m_ff_order
 
double m_ff_reach = 0.
 

Static Private Attributes

static constexpr size_t kValueStripes = 1024
 

Detailed Description

The band-volume integral of one cell, in closed form:

J(t) = int_t (d(x) - delta) dV,   d = Euclidean distance to the input triangle mesh.

A port of the VALUE path of the Python reference exact_mesh.integrate_mesh (and of the exact_tri closed forms it calls), scratchpad exact_integral/ of 2026-10-10/11: same algorithm, same switch constants, same operation order, so it reproduces the reference's numbers to rounding (tests/test_exact_band_integral.cpp). Used by EXPERIMENTAL_band_volume_rule "exact" (the band cell term) and, through max_distance(), by the settle loop's max test.

Features and local regions. The input's features are its face interiors, edges and vertices (duplicate vertices merged). The local region L_g of a feature g is an intersection of half-spaces built from its incident features only: a face's prism (inside the planes through its edges perpendicular to it), an edge's slab between the planes through its ends perpendicular to it, cut by the plane through the edge perpendicular to each incident face (away from that face's third vertex), a vertex's cone {x : (x - v).(w - v) <= 0 for every edge (v, w)}. Two facts make d = min over {g : x in L_g} of d_g exact, d_g the plane, line or point distance of g: (i) the feature holding x's nearest point in its relative interior has x in its region, and d_g(x) = d(x); (ii) on L_g, d_g is the distance to an actual point of g, so d_g >= d.

Per cell: 0. Candidates: U = min over triangles P of max over t's corners of d_P is an upper bound of d on t (d_P convex), so every feature whose bounding box is within U of t's box is kept. U is the exact min over ALL triangles (a box search); the Python takes the min over the 32 triangles nearest t by box distance, MEASURED equal on all 14180 cells checked (the five stored cases, sample + 3000 random each), although ties at rank 32 occur in up to 634 of 3240 cells, where numpy's sort order decides which 32 it takes.

  1. t is cut by the candidates' local regions into convex pieces of constant member set S = {g : piece inside L_g}. Members that cannot attain the minimum on a piece are dropped (lower bound >= another member's upper bound); this changes no value.
  2. |S| = 1: the closed form of d_g. S all faces: split by the planes and the bisectors of the (then affine) distances, exact. S all vertices: split by the bisector planes, exact.
  3. Otherwise ("rule (a)") the boundary between members is curved and the piece returns min over g in S of int_piece d_g >= int_piece d: an UPPER BOUND, not the integral. Stats::rule_a_vol reports its volume (0.15-0.35% of the band volume on t100026).

One-feature integrals (exact_tri.py): the face's |n.(x - a)| is affine on each side of its plane (volume times centroid value); the line and point distances by Euler's theorem for degree-1 homogeneous integrands, int_Q f = 1/4 sum_F h_F int_F f dA, faces by the divergence theorem in their plane, edge integrals in sqrt, asinh and atan. Two pieces are convergent series with explicit truncation bounds, not closed forms: a face nearly parallel to an edge line (eps_F < 0.1) uses a Taylor series in the variation of the line's height over the face, per edge either along the edge (ratio <= 1/4, at most 29 terms) or in eta (ratio < 1/20, at most 13 terms), each stopped at its edge's actual ratio with the same tail bound.

Conditioning (Python, test_exact_tri.py "far"): a piece of size L at distance D from the singular point or line loses about eps (D/L)^2 in the Euler sums.

The offset side (constructed with a side): the band B is the region between the input and the front, so a point on the far side of the input surface from the offset is not in it, and value() returns J(t) = int_{t cap B} (d - delta) dV. The side of x is decided by its nearest feature g, by the sign of (x - c).N_g for its nearest point c (the pseudonormal test, Baerentzen-Aanaes 2005): N_g = the face normal (face), n1 + n2 (edge), the angle-weighted pseudonormal (vertex). On g's local region c is g's own nearest point to x, so the test is the fixed plane {(x - q_g).N_g = 0}, q_g a point of g:

Thread safety: value() and value_grad_hess() are const. Their state is a per-thread scratch partition and value()'s table of results, whose slots are read and written under a lock (value()); concurrent calls are safe. A Partition (below) is the caller's, used by one thread.

Constructor & Destructor Documentation

◆ ExactBandIntegral() [1/2]

wmtk::components::topological_offset::ExactBandIntegral::ExactBandIntegral ( const Eigen::MatrixXd &  V,
const Eigen::MatrixXi &  F 
)
inline

V (n x 3) and F (m x 3): the input triangles. Vertices are merged by exact coordinates and sorted (numpy.unique, as the Python Mesh does), which fixes the order the features are visited in – the rule-(a) pieces depend on it.

◆ ExactBandIntegral() [2/2]

wmtk::components::topological_offset::ExactBandIntegral::ExactBandIntegral ( const Eigen::MatrixXd &  V,
const Eigen::MatrixXi &  F,
const std::vector< int8_t > &  face_side,
int  sigma,
size_t  value_slots = 0,
std::shared_ptr< const wmtk::Envelope >  envelope = nullptr 
)

With the offset side (class doc): face_side[f] = +1 if row f's normal (b - a) x (c - a) points out of the solid the triangles bound, -1 if into it, 0 for a triangle that bounds no solid; sigma = +1 for the band outside that solid, -1 inside it, 0 no clip (as the two-argument constructor). TopoOffsetTetMesh's solid is its label-1 cells, which the band is outside of for offset_out and offset_in alike, so it passes +1. value_slots > 0: value() keeps a table of its results of at least that many slots (the value table, value()). envelope: the triangles' box queries, for U and the candidate query – a Triangles3d Envelope whose primitive i is row i of F (TopoOffsetTetMesh passes m_input_complex_envelope, built from the same rows); null: one is built here from V and F.

Member Function Documentation

◆ cell_partition()

const ExactBandIntegral::Work * wmtk::components::topological_offset::ExactBandIntegral::cell_partition ( const std::array< Eigen::Vector3d, 4 > &  t,
Stats *  stats,
Work *  own,
Partition *  keep 
) const
private

partition() of t (null: t is flat): into own with stats (which counts every partition), else read from or written to keep when given (Partition), else into a per-thread scratch partition (its storage reused from call to call).

◆ check_cell_pieces()

void wmtk::components::topological_offset::ExactBandIntegral::check_cell_pieces ( const std::array< Eigen::Vector3d, 4 > &  t,
double  delta,
const Work &  w,
double  vol_sum,
double  empty_vol 
) const
private

The checks of value() on t's pieces (volumes summed by the caller), and of max_distance() on f's pieces (areas): throw with the corners in hex floats if the pieces do not tile, or leave more outside every region, than the partition's tolerances allow.

◆ distance_bound()

double wmtk::components::topological_offset::ExactBandIntegral::distance_bound ( const std::array< Eigen::Vector3d, 4 > &  t) const
inline

U = min over the input triangles P of max over t's corners of d_P: an upper bound of d on t (each d_P is convex, and d <= d_P), the bound value()'s candidate search starts from.

◆ front_face()

double wmtk::components::topological_offset::ExactBandIntegral::front_face ( const std::array< Eigen::Vector3d, 3 > &  f,
double  delta,
FaceParts *  keep = nullptr 
) const

front_face(): int over the triangle f of G.n dA, n = (f1 - f0) x (f2 - f0) / |.| (f ordered with the normal pointing out of the band). front_face_derivs(): for the motion of corner kv (the others fixed), the gradient and the one-vertex Hessian of E's dependence through f: grad = n int_f chi (d - delta) phi dA, hess = n (x) int_f chi phi^2 grad d dA + (int_f chi (d - delta) phi dA / |N|) dN/dx

  • sum over cut edges c: n (x) g_c int_c (d - delta) phi^2 ds / |g_c,f|, phi the hat function of corner kv, chi the offset side's indicator, N = (f1 - f0) x (f2 - f0) with column l of dN/dx = e_l x (x_a - x_b) (f ordered (x, x_a, x_b)), and the cut edges the lines where f crosses an input face's plane into the far side (chi (d - delta) jumps by delta there; g_c the plane's normal out of the kept side, g_c,f its part in f's plane). Summed over the band's boundary faces through x these are E(B)'s gradient and Hessian in x: Reynolds' transport theorem on int_B chi (d - delta), the boundary moving with velocity phi; d is Lipschitz, so no medial-axis term and no D_t term. A part of f lying on the input (d = 0 on it) takes grad d from the band side (the side the band is on, the offset side with a side; -n without one), the one-sided limit, as value_grad_hess(). Throws on a curved bisector (above) or if f's pieces do not tile it (max_distance()). With keep, f's labelled parts are read from or written to it (FaceParts).

◆ front_flux_flag()

bool wmtk::components::topological_offset::ExactBandIntegral::front_flux_flag ( const Eigen::Vector3d *  t,
int  n 
) const

The same test for the n points t: their box and their side of each plane. A subset of the points is flagged only if the points are, so the points of an operation's ring unflagged leave every cell made from them unflagged.

◆ label_face()

void wmtk::components::topological_offset::ExactBandIntegral::label_face ( const std::array< Eigen::Vector3d, 3 > &  f,
FaceWork &  fw 
) const
private

front_face()'s labelled parts of f into fw: the partition, each piece resolved to its nearest feature, the offset side kept.

◆ localize()

void wmtk::components::topological_offset::ExactBandIntegral::localize ( const Eigen::Vector3d *  t,
int  n,
Local &  w,
Stats *  stats 
) const
private

The candidates of the n points t (a cell's or a face's corners) in the frame of w.c0, set by the caller: U, the box query, the local features and half-spaces, the rounding scale.

◆ max_distance()

double wmtk::components::topological_offset::ExactBandIntegral::max_distance ( const std::array< Eigen::Vector3d, 3 > &  f,
MaxInfo *  info = nullptr 
) const

max over the triangle f of d (exact_mesh.max_on_triangle), the settle loop's max test. f is cut by the candidates' local regions as a cell is (the same search, region tests, splits, tolerances and scale rule; f a planar convex ring in place of a polytope), and d is convex wherever one member's distance is d, so on each piece the max is at a vertex of the piece:

  • one member: the max of d_g over the piece's vertices, exact;
  • members all faces, or all vertices: split by the bisectors as in value(), each sub-ring one affine or point distance, exact;
  • otherwise (rule (a), the boundary between members curved): min over members g of the max of d_g over the piece's vertices, an upper bound on max of d there (d <= d_g). The max over pieces is exact up to rounding unless it comes from a rule-(a) piece; never below the true max. One difference from the cell's partition: a ring lying on a region's boundary plane counts as inside that region (a point of the plane is in both closed regions); a duplicated piece cannot lower a max, a lost one can.

The former bound, U = min over P of max over f's corners of d_P (MaxInfo::U), is d_P's max for the single best triangle P; it overshoots where f straddles a coplanar edge of the input, by about s^2 / (2 delta) for a straddle s. MEASURED, cube outward at turn 28: all 8 faces it marked were 1.06-1.26 bars by U and -0.016..+0.020 bars by this max (the dense sampled max agrees).

Throws (with f in hex floats) if the pieces do not tile f, or leave more of f outside every region, than the tolerances allow (the checks of value(), on areas).

◆ partition()

bool wmtk::components::topological_offset::ExactBandIntegral::partition ( const std::array< Eigen::Vector3d, 4 > &  t,
Work &  w,
Stats *  stats 
) const
private

_partition: the candidates in t's frame and the convex pieces of t with member sets; false for a flat cell.

◆ reserve_values()

void wmtk::components::topological_offset::ExactBandIntegral::reserve_values ( size_t  slots) const

Grow the value table (value()) to at least slots slots, emptied; no table, or one that large already: nothing. Not thread-safe: called between passes. A table sized to the constructed mesh only answers few calls once the mesh has grown. MEASURED (cube 1e-2 / 1e-4, front_flux, 15 rounds, table sized at construction, 380k tets late): the smoothing vetoes' value() calls hit it 1.6-2.3% of the time, the operations' 65%.

◆ value()

double wmtk::components::topological_offset::ExactBandIntegral::value ( const std::array< Eigen::Vector3d, 4 > &  t,
double  delta,
Stats *  stats = nullptr 
) const

J(t) = int_t (d - delta) dV for the cell with corners t (either orientation), restricted to the offset side when constructed with one (class doc); 0 for a flat cell (|6 vol| <= 64 eps L^3, L its longest edge). With stats, adds to it.

The value table (constructed with value_slots > 0; not used with stats, whose counters count every evaluation): J is a function of its 13 inputs alone – t's 12 coordinates in their order, delta – and of the input triangles, fixed. A slot, chosen by a hash of the inputs, holds the last result with its inputs; a call whose inputs equal a slot's, bit for bit, returns its result, which is what the evaluation would return again. Any other call evaluates and takes the slot over: a cell that moved or two cells sharing a slot cost an evaluation, never a different value.

Why: the energy rule reads the band cells of an operation's ring before it, and an unchanged cell is read again by every later operation whose ring holds it. MEASURED (Geneva base, inward, exact rule, the turn-1 collapse group, every evaluation of value() logged by its inputs): the collapse before-sums made 8.5M calls (6.2 band cells per sum), every one of them a repeat of an earlier call, 83% of the group's value() time; the after-sums 0.69M, 62% repeats (a collapse refused, retried in a later round). A table taking every result, of 2^18 / 2^20 / 2^22 slots, would have answered 98.2 / 99.5 / 99.9% of the before-sums and 52 / 59 / 61% of the after-sums.

◆ value_grad_hess()

double wmtk::components::topological_offset::ExactBandIntegral::value_grad_hess ( const std::array< Eigen::Vector3d, 4 > &  t,
int  kv,
double  delta,
Eigen::Vector3d &  grad,
Eigen::Matrix3d &  hess,
Stats *  stats = nullptr 
) const

J and its exact gradient and Hessian with respect to corner kv of t, the other three fixed (exact_mesh.value_grad_hess): Reynolds' transport theorem on each smooth piece, a boundary integral over the three faces of t through x = t[kv], plus, on the Hessian, the terms of piece edges sliding over those faces ("cut edges"; they cancel in pairs between exact pieces and remain on rule-(a) pieces). J here sums the same pieces split into smooth parts, so it equals value() to rounding.

Where the derivative is not the derivative of J:

  • rule-(a) pieces: it is the derivative of the BOUND (the chosen member's integral over the piece). The bound is not smooth where the chosen member switches; the gradient there is one member's.
  • a kink of d lying on a face of t through x (a cell face on an input plane, or on a bisector): J is one-sided C^2; the Hessian is the limit for x moving INTO t (the trace of grad d from inside t). With the offset side: each kept piece integrates d - delta, the side planes being fixed faces of the pieces whose cut edges keep their terms (the integrand jumps to 0 across them); a disagreeing rule-(a) part D takes the side of the member nearest at its centroid (class doc): dropped, or a rule-(a) part over the members that put it on the offset side. The side can switch where that member does, so J is not smooth there. Flat cells give J = 0 and zero derivatives.

◆ value_grad_hess_impl()

double wmtk::components::topological_offset::ExactBandIntegral::value_grad_hess_impl ( const std::array< Eigen::Vector3d, 4 > &  t,
int  kv,
double  delta,
Eigen::Vector3d &  grad,
Eigen::Matrix3d &  hess,
Stats *  stats,
Partition *  keep,
bool  want_value 
) const
private

value_grad_hess() with cell_partition()'s keep; want_value false (grad_hess()) skips J's integration over the elementary pieces and returns NaN.

Member Data Documentation

◆ m_env

std::shared_ptr<const wmtk::Envelope> wmtk::components::topological_offset::ExactBandIntegral::m_env
private

The triangles' boxes, for U and the candidate query: the envelope's Envelope::primitives_in_box(), primitive f being face f. Until 2026-10-15 a tree of this class's own over the same boxes, beside the envelope's.

◆ m_face_feats

std::vector<std::array<int, 6> > wmtk::components::topological_offset::ExactBandIntegral::m_face_feats
private

per face: its 3 edges, its 3 vertices

◆ m_feat

std::vector<Feature> wmtk::components::topological_offset::ExactBandIntegral::m_feat
private

faces, then edges, then vertices (the Python's order)

◆ m_hs

std::vector<std::pair<Eigen::Vector3d, Eigen::Vector3d> > wmtk::components::topological_offset::ExactBandIntegral::m_hs
private

Half-spaces as (unit normal g, point q on the plane). A cell takes the offset in its own frame, h = g.(q - c0), c0 its centroid: g.q - g.c0 in global coordinates carries eps |x_global|, which exceeds the clip tolerance 16 eps (|h| + max|V|) of the local frame when the input is large against the cell (t100026: |x| <= 143, cells ~1). On a plane two features share (a face's prism plane through an edge = that edge's wedge plane), in/out was then rounding noise deciding how a rule-(a) piece is cut: MEASURED, one t100026 cell differed from the Python by 7.4e-5 while every exact cell agreed to 1e-14. Fixed the same way in the Python (exact_mesh.Mesh, _partition).

◆ m_id

uint64_t wmtk::components::topological_offset::ExactBandIntegral::m_id = 0
private

This integral's number among all constructed, the owner a Partition records (an address can be reused by a later integral).

◆ m_pad

double wmtk::components::topological_offset::ExactBandIntegral::m_pad = 0.
private

1e-9 of the input's diagonal: what a box query is grown by, so that a triangle whose distance reaches a bound by rounding is never left out of it.

◆ m_sigma

int wmtk::components::topological_offset::ExactBandIntegral::m_sigma = 0
private

The offset side (class doc): sigma (0: none), and per feature its side plane, the unit normal N oriented out of the solid (face_side) and a point q on it; m_side_has[g] false where the feature has no plane (every point counts).


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