|
Wildmeshing Toolkit
|
The offset term of the smoothing objective: w * (Phi(x) - c)^2. More...
#include <OffsetPotential.hpp>
Public Types | |
| using | VecD = Eigen::Matrix< double, DIM, 1 > |
| using | MatD = Eigen::Matrix< double, DIM, DIM > |
Public Member Functions | |
| OffsetEnergy (const std::shared_ptr< const OffsetPotential< DIM > > &potential, double weight=1., bool gauss_newton=true, bool distance_residual=false, bool one_sided=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 | |
| void | residual (const VecD &p, double &r, VecD &dr) const |
| r and its gradient under either residual (see the constructor). | |
Private Attributes | |
| std::shared_ptr< const OffsetPotential< DIM > > | m_potential |
| double | m_weight |
| bool | m_gauss_newton |
| bool | m_distance_residual |
| bool | m_one_sided |
The offset term of the smoothing objective: w * (Phi(x) - c)^2.
A polysolve::nonlinear::Problem in the shape of ExactDistanceEnergy2D/3D, so the shared smoother composes it into its EnergySum beside AMIPS with no special case, which is what lets a front vertex take the same path as every other vertex.
The residual form rather than Phi itself: Phi is a barrier, so minimising it would drive the vertex to infinity and maximising it into the complex, while the squared residual has its minimum exactly on the level set, where the front belongs.
Value, gradient and Hessian all follow from Phi, grad Phi and hess Phi by the chain rule:
E = w (Phi - c)^2 grad = 2 w (Phi - c) grad Phi hess = 2 w [ grad Phi grad Phi^T + (Phi - c) hess Phi ]
The second Hessian term changes sign with the residual and can make H indefinite far from the level set; gauss_newton drops it, leaving the always-PSD outer product. On by default: the dropped term vanishes at the solution, so it costs nothing at convergence and buys a descent direction everywhere.
| wmtk::components::topological_offset::OffsetEnergy< DIM >::OffsetEnergy | ( | const std::shared_ptr< const OffsetPotential< DIM > > & | potential, |
| double | weight = 1., |
||
| bool | gauss_newton = true, |
||
| bool | distance_residual = false, |
||
| bool | one_sided = false |
||
| ) |
distance_residual charges the signed distance from x to the level set along the field's normal, over delta – what (d - delta)/delta already is for the Euclidean field – instead of the value ratio (Phi - c)/c, which for the smooth field is a barrier value and not a length, and pulls far harder where two fronts are pressed together. Same level set and same root either way; only the charge changes. Both dimensions' front placement passes true.
one_sided charges only points on the input's side of the level set (is_inside_offset()): beyond it the term and its derivatives are zero, so the term pushes a vertex out to the level set and never pulls one in. C^1 at the level set, where the residual is zero from both sides. The repulsion passes before the march use it (TopoOffsetTetMesh::repulsion_smoothing()).