|
| | BandVolumeEnergy3D (std::shared_ptr< const Envelope > env, double pad, std::vector< Cell > cells, const Eigen::Vector3d &x0, double delta) |
| |
|
double | value (const TVector &x) override |
| |
|
void | gradient (const TVector &x, TVector &gradv) override |
| |
|
void | hessian (const TVector &x, THessian &hessian) override |
| |
|
void | hessian (const TVector &x, MatrixXd &hessian) override |
| |
|
void | solution_changed (const TVector &new_x) override |
| |
|
void | set_exact_integral (std::shared_ptr< const ExactBandIntegral > eb, double delta) |
| | EXPERIMENTAL_band_volume_rule "exact": a cell's Vol_t m_t becomes J_t / delta, J_t = int_t (d - delta) dV in closed form (ExactBandIntegral), the moving vertex x one of t's corners – the term band_cell_term() reads. Values from ExactBandIntegral::value(), the function band_cell_term() calls (the corners in another order); gradient and Hessian from ExactBandIntegral::value_grad_hess() in x (its J equals value() to rounding): exact, except on rule-(a) pieces (the bound's derivative) and at a kink of d on a face of t through x (the one-sided limit for x moving into t). The last point's value, and its gradient and Hessian, are kept: polysolve asks for each separately at one x. The corner bound's minima and certified ball are not used.
|
| |
| void | set_front_flux (std::shared_ptr< const ExactBandIntegral > eb, double delta, std::vector< Face > faces) |
| | EXPERIMENTAL_band_volume_rule "front_flux": the front form of the same band term (ExactBandIntegral.hpp): the value is (sum over the band's boundary faces f through x of int_f G.n dA.
|
| |
| void | set_swept (std::shared_ptr< const ExactBandIntegral > eb, double delta, std::vector< std::array< Eigen::Vector3d, 2 > > faces, SweptDerivCounts *counts) |
| | EXPERIMENTAL_band_volume_rule "exact_swept": the smoother's search model is the function the move is judged on (TopoOffsetTetMesh::swept_accept()). Its value at x is swept_change(x0, x) over faces, x0 the position at construction: (E(B(x)) - E(B(x0))) / delta, E(B) = int_B chi (d - delta) dV, exactly where value() integrates every piece exactly. Its gradient and Hessian are E(B)'s at x by Reynolds' transport theorem: the sum over f of ExactBandIntegral::front_face_derivs((x, a_f, b_f), delta, 0) / delta, the "front_flux" rule's derivative, no D_t term (d is Lipschitz). Each face's normal stays out of B at every x the solver evaluates, where no ring cell is inverted (polysolve tests is_step_valid() before each trial value). Defined at x = x0 too, where every swept tet is flat and its own value_grad_hess() would be 0.
|
| |
|
std::pair< Eigen::Vector3d, double > | certified_ball () const |
| | The current certified ball, its centre and radius (radius < 0: none yet). For the tests.
|
| |
|
|
double | eval (const Eigen::Vector3d &x, int need, Eigen::Vector3d &g, Eigen::Matrix3d &H) const |
| | need: 0 value, 1 + gradient, 2 + Hessian.
|
| |
|
void | exact_minima (const Eigen::Vector3d &x) const |
| | m_min_md and m_min_tri at x (see the class comment).
|
| |
| bool | certify_ball (const Eigen::Vector3d &x) const |
| |
|
double | ff_eval (const Eigen::Vector3d &x, int need, Eigen::Vector3d &g, Eigen::Matrix3d &H) const |
| | The front form's value / derivatives at x (eval()).
|
| |
|
double | sw_eval (const Eigen::Vector3d &x, int need, Eigen::Vector3d &g, Eigen::Matrix3d &H) const |
| | The "exact_swept" model's value / derivatives at x (eval()).
|
| |
|
|
std::shared_ptr< const Envelope > | m_env |
| | the input's primitives
|
| |
|
double | m_pad = 0. |
| | input_pad() of the input
|
| |
|
double | m_delta = 1. |
| |
| std::vector< int64_t > | m_hint |
| |
| bool | m_min_set = false |
| |
|
Eigen::Vector3d | m_min_x = Eigen::Vector3d::Zero() |
| |
|
std::vector< double > | m_min_md |
| |
|
std::vector< int64_t > | m_min_tri |
| |
|
Eigen::Vector3d | m_ball_c = Eigen::Vector3d::Zero() |
| | certify_ball(): the ball's centre and radius (< 0: none), and per cell its candidates.
|
| |
|
double | m_ball_r = -1. |
| |
|
std::vector< std::vector< BallCandidate > > | m_ball_cand |
| |
|
std::shared_ptr< const ExactBandIntegral > | m_eb |
| | set_exact_integral(): the integral, and the last point's value / gradient and Hessian.
|
| |
| std::vector< ExactBandIntegral::Partition > | m_eb_parts |
| |
|
bool | m_eb_val_set = false |
| |
|
bool | m_eb_der_set = false |
| |
|
Eigen::Vector3d | m_eb_val_x = Eigen::Vector3d::Zero() |
| |
|
Eigen::Vector3d | m_eb_der_x = Eigen::Vector3d::Zero() |
| |
|
double | m_eb_E = 0. |
| |
|
Eigen::Vector3d | m_eb_g = Eigen::Vector3d::Zero() |
| |
|
Eigen::Matrix3d | m_eb_H = Eigen::Matrix3d::Zero() |
| |
| bool | m_ff = false |
| |
|
std::vector< Face > | m_ff_faces |
| |
| std::vector< ExactBandIntegral::FaceParts > | m_ff_fparts |
| |
|
std::vector< double > | m_ff_U |
| |
|
std::vector< Eigen::Vector3d > | m_ff_Ux |
| |
|
std::vector< char > | m_ff_Ux_set |
| |
| bool | m_sw = false |
| |
|
std::vector< std::array< Eigen::Vector3d, 2 > > | m_sw_faces |
| |
|
std::vector< ExactBandIntegral::FaceParts > | m_sw_fparts |
| |
|
SweptDerivCounts * | m_sw_counts = nullptr |
| |
|
Eigen::Vector3d | m_x0 = Eigen::Vector3d::Zero() |
| | The moving vertex's position at construction.
|
| |
|
std::vector< Cell > | m_cells |
| |
A vertex's part of the energy's band term (TopoOffsetTetMesh::band_cell_term()), the vertex moving:
E(x) = sum over the vertex's band cells t of Vol_t(x) * m_t(x),
m_t(x) = min over ALL input triangles P of (1/4) sum over t's 4 corners q of
(d_P(q) - delta) / delta,
the four corners being x and the cell's three fixed ones, Vol_t the cell's signed volume, positive on a valid cell. Each cell's term is band_cell_term() at x, so the solve descends exactly the cell terms E sums.
Vol_t(x) = (q1 - x) . ((q2 - q1) x (q3 - q1)) / 6 is affine in x: its gradient is -(q2 - q1) x (q3 - q1) / 6 and its Hessian zero. The gradient and Hessian of m_t are the minimising triangle P's: grad m_t = grad d_P(x) / (4 delta), hess m_t = hess d_P(x) / (4 delta). So grad E_t = m_t grad Vol + Vol grad m_t and hess E_t = grad Vol grad m_t^T + grad m_t grad Vol^T + Vol hess m_t. The outer-product pair is indefinite in general; polysolve's Newton regularises, and the AMIPS term beside it carries the shape.
Every value, gradient and Hessian equals, bit for bit, that of a min_mean_distance() call per cell and evaluation; the work behind them is cut twice (exact_minima()):
- the last point's minima are kept, so value, gradient and Hessian at one x (polysolve asks for each separately, and again in its line search) search once;
- each cell searches only its certified candidates (ball_candidates()), valid at every x in a ball around the point they were built at. r, the ball's radius, is the distance from that point to the nearest plane through a cell's three fixed corners: the largest ball around it in which none of these cells can invert. The solver evaluates only points where no ring cell is inverted (polysolve tests is_step_valid() before each trial value), so it leaves this ball only away from the nearest face. Correctness does not depend on r, only the speed. Outside the ball the candidates are rebuilt around the new point; where no ball can be certified there (r <= 0 or not finite), that evaluation runs min_mean_distance() itself. Measured on the cube (cube_on, 3 turns, serial): 7.45M evaluations, 57% at the last point; of the rest 96% inside the ball, with 1.37 candidates per cell; the whole tree 8 times. Smoothing 68 s -> 15 s, the run 76 s -> 23 s, the output bit-identical.
| void wmtk::components::topological_offset::BandVolumeEnergy3D::set_swept |
( |
std::shared_ptr< const ExactBandIntegral > |
eb, |
|
|
double |
delta, |
|
|
std::vector< std::array< Eigen::Vector3d, 2 > > |
faces, |
|
|
SweptDerivCounts * |
counts |
|
) |
| |
EXPERIMENTAL_band_volume_rule "exact_swept": the smoother's search model is the function the move is judged on (TopoOffsetTetMesh::swept_accept()). Its value at x is swept_change(x0, x) over faces, x0 the position at construction: (E(B(x)) - E(B(x0))) / delta, E(B) = int_B chi (d - delta) dV, exactly where value() integrates every piece exactly. Its gradient and Hessian are E(B)'s at x by Reynolds' transport theorem: the sum over f of ExactBandIntegral::front_face_derivs((x, a_f, b_f), delta, 0) / delta, the "front_flux" rule's derivative, no D_t term (d is Lipschitz). Each face's normal stays out of B at every x the solver evaluates, where no ring cell is inverted (polysolve tests is_step_valid() before each trial value). Defined at x = x0 too, where every swept tet is flat and its own value_grad_hess() would be 0.
Where front_face_derivs() throws at x – a curved bisector crossing a piece of a face (not logged, ExactBandIntegral::QuietCurvedBisector), or a face's pieces not tiling it – the derivatives at that x are the "exact" rule's: the sum over the ring's band cells of ExactBandIntegral::grad_hess(t, 0) / delta, the derivative of the same E(B) up to the cells that do not move (the bound's on rule-(a) pieces). Every derivative evaluation is counted into counts, and those that took the ring cells'. The last point's value, and its gradient and Hessian, are kept.
Why: the former model, the 7-point rule of G = psi(d) grad d over the front faces with each rule point's feature kind frozen at x0, differed from the judged function by the jumps of G.n across the bisectors, which it left out. MEASURED with it (uk-sonic, screw piece 15, 8 threads, 5 turns, 2026-10-23): 4,752 of turn 2's 44,974 front solves refused after 4 halvings (10.6%); the ring max held at one vertex, (2.169, -16.6, 3.056), through turns 1-3 at 7.03 / 5.96 / 5.71x, against the "exact" rule's ring max 8.73 / 3.20 / 2.66x.
| double wmtk::components::topological_offset::BandVolumeEnergy3D::swept_change |
( |
const ExactBandIntegral & |
eb, |
|
|
double |
delta, |
|
|
const Eigen::Vector3d & |
x0, |
|
|
const Eigen::Vector3d & |
x1, |
|
|
const std::vector< std::array< Eigen::Vector3d, 2 > > & |
faces, |
|
|
ExactBandIntegral::Stats * |
st = nullptr |
|
) |
| |
|
static |
"exact_swept": the band term's change for the vertex moving from x0 to x1, dE* / delta = ( sum over f of sign_f value(conv(x0, x1, a_f, b_f), delta) ) / delta, f = (x, a_f, b_f) the boundary faces of the band B through the vertex, ordered with their normal (a_f - x0) x (b_f - x0) out of B (TopoOffsetTetMesh::band_swept_faces()), sign_f the sign of (x1 - x0) along it by exact orient3d, a flat swept tet skipped (TopoOffsetTetMesh, EXACT SWEPT CHANGE). value() with a Stats (st, or a local one), which keeps the value table out of the swept tets: no other call asks for them again. The one function both the decisions (TopoOffsetTetMesh::band_swept_sum()) and the smoother's search model (set_swept()) evaluate.