|
Wildmeshing Toolkit
|
THE offset term of a 2D front vertex's smoothing objective: the mean squared relative error of the field over the stencil of each incident front chord. More...
#include <OffsetPotential.hpp>
Classes | |
| struct | Edge |
| One incident front chord, the moving vertex implicit. More... | |
| struct | Reading |
| struct | Sample |
One stencil point's barycentric weights. a is the moving vertex's, so dq_i/dx = a_i I. More... | |
Public Member Functions | |
| StencilEnergy2D (const std::shared_ptr< const OffsetPotential2D > &potential, std::vector< Edge > edges, double weight, bool gauss_newton=false) | |
| 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 |
Private Member Functions | |
| const std::vector< Reading > & | readings_at (const Eigen::Vector2d &x, bool need_dr) const |
Private Attributes | |
| std::shared_ptr< const OffsetPotential2D > | m_potential |
| std::vector< Edge > | m_edges |
| double | m_weight |
| bool | m_gauss_newton |
| double | m_c = 1. |
| the potential's target level, cached | |
| std::vector< Reading > | m_readings |
| Eigen::Vector2d | m_readings_x |
| bool | m_readings_valid = false |
| bool | m_readings_have_dr = false |
THE offset term of a 2D front vertex's smoothing objective: the mean squared relative error of the field over the stencil of each incident front chord.
E(x) = w * sum over the vertex's incident front chords e of
(1/N_s) * sum over e's N_s stencil points i of r(q_i(x))^2
r(p) = (Phi(p) - c) / c, q_i(x) = a_i x + b_i q1
with (a_i, b_i) the barycentric weights of stencil point i on the chord, a_i the MOVING vertex's own weight, and q1 the chord's other end, fixed for the visit. The stencil is TopoOffsetTriMesh::for_each_edge_sample, sized by stencil_order.
UNITS: the front smoother passes w = 1 / front_conv_frac()^2 (TopoOffsetTriMesh::offset_term_weight()), which puts r in units of the tolerance: each chord's term is then TopoOffsetTriMesh::edge_offset_term(), 1 at the bar, the term the per-cell energy tri_energy() adds to the chord's band face, and E is the sum of those terms over the vertex's chords. Exactly so for the euclidean field, where r IS relative_residual().
THIS ONE TERM REPLACES BOTH the placement term (OffsetEnergy2D on the vertex alone) and the sag term over the chord interiors that preceded it, because the stencil contains the ends: at order 0 the stencil IS the two ends, so E is exactly the placement residual of the vertex and its neighbours, and every higher order adds interior points that ask the same question between them.
r IS THE PLAIN RELATIVE ERROR (Phi - c)/c, which for the euclidean field is exactly (d - target_distance)/target_distance – the same residual OffsetEnergy2D uses there. For the SMOOTH field OffsetEnergy2D instead divides by g_ref * delta to get a monotone length; this class does not, so under offset_field: "smooth" the two are scaled differently (about 3.44x the criterion's number at the default offset_dhat_factor).
NOTE THE PER-CHORD MEAN, SUMMED OVER CHORDS, with no length weight: a vertex with V incident chords contributes its own r(x)^2 with coefficient V/N_s, since it is a stencil point of every one of them.
The derivatives are exact, and so is the Hessian by default: per stencil point 2 a_i^2 (dr dr^T + r hess Phi / c), whose second term is indefinite where r < 0 (inside the level set). gauss_newton drops that term, leaving the sum of a_i^2 dr dr^T outer products, PSD by construction – the form used until 2026-09-28; hessian() says why the default changed.
|
private |
Every stencil point's reading at x, chords in order and each chord's samples in order, computed once per x: polysolve asks value, gradient and Hessian at the same x in one Newton iteration (and value once more in its gradient check), and the line search's accepted point is the next iteration's x. The field is read without its gradient until a gradient or Hessian is asked for, then with it in one value_gradient() call.