Wildmeshing Toolkit
Loading...
Searching...
No Matches
OptimizerParameters.h
1#pragma once
2
3#include <limits>
4#include <string>
5#include <wmtk/utils/Logger.hpp>
6
7namespace wmtk {
8
29{
30 double epsr = 1e-3; // relative error bound (wrt diagonal)
31 double eps = -1.; // absolute error bound
32 double lr = 5e-2; // target edge length (relative)
33 double l = -1.;
34 double l_min = -1;
35 double diag_l = -1.;
36
37 bool preserve_topology = false;
38
65
72
73 // ---- Stuck-element sizing refinement --------------------------------
74 // Trigger threshold: fire when the last iteration's improvement is small compared
75 // with the distance the max energy still has to cover, i.e. refine when
76 // (prev_max - max) <= stall_eps * (max - target).
77 // Equivalently: refine unless the mesh is on course to reach the target within
78 // about 1/stall_eps more iterations. 0 => only when it does not improve at all.
79 //
80 // The denominator is the remaining distance, not prev_max, and that is the whole
81 // point. Measured against prev_max, a mesh grinding down at a steady 1.3% per
82 // iteration toward a target far below clears a 1% bar every single iteration and so
83 // never looks stalled -- even though at that rate it needs on the order of a hundred
84 // more iterations and the operations have in fact deadlocked. The escape hatch then
85 // never fires, which is exactly the regime it exists for.
86 double stuck_refine_stall_eps = 0.1;
87 // Cooldown: after a refinement, skip this many improvement iterations before
88 // refining again, so the operations get full passes to act on the new sizing
89 // field before more refinement is added. 0 => may refine every iteration.
90 //
91 // 1, because refining every iteration can outrun the operations entirely. On
92 // triwild20k 189017 at eps_rel 1e-4 the field ratchets down faster than split and
93 // collapse can act on it: the mesh sits at ~31k faces for a dozen iterations, then
94 // runs away 54k -> 96k -> 159k -> 5.8M and never converges, its max energy pinned at
95 // the inverted sentinel. At cooldown 1 the same run climbs deliberately to 181k and
96 // converges at 9.9994 in 35 iterations. Cooldown is the narrow instrument for this:
97 // it slows the refinement rather than licensing collapse to undo refinement.
98 //
99 // Cost, measured over the 31 challenging models at stop_energy 10, cooldown 0 -> 1:
100 //
101 // tetwild iterations 185 -> 196 (+5.9%) elements -1.8% wall -5.3%
102 // triwild iterations 166 -> 173 (+4.2%) elements -0.1% wall -6.2%
103 //
104 // A few percent more iterations, slightly fewer elements, and no wall-time cost -- the
105 // extra iterations are cheaper ones. 1 is the knee: 2 and 3 buy a further 2-4% element
106 // reduction in tetwild for +34% and +76% iterations.
107 //
108 // This supersedes an earlier reading of a 468-model triwild20k sweep, where cooldown 1
109 // cost ~13% wall for identical mesh sizes and was taken as evidence that a cooldown
110 // only delays the next escape. That holds where the escape hatch is not load-bearing;
111 // it does not hold on the models where it is.
112 int stuck_refine_cooldown = 1;
113 // Number of worst cells (by energy) whose neighborhoods are refined.
114 int stuck_refine_num_worst = 0;
115 // Graph rings around each worst cell's vertices included in the refinement.
116 int stuck_refine_rings = 0;
117 // Multiplicative reduction of m_sizing_scalar per refinement (0.5 => /2).
118 double stuck_refine_factor = 0.5;
119 // Lower bound on m_sizing_scalar. Much smaller than the old l_min/l floor;
120 // still far above the position-rounding scale so it stays numerically safe.
121 double stuck_refine_min_scalar = 1e-3;
122 // Gradation cap for the monotone sizing smoothing: neighboring sizings may
123 // differ by at most this factor. The smoothing only ever *lowers* sizings
124 // (spreads refinement outward), never raises the refined values, avoiding
125 // sharp resolution jumps that make operations ill-conditioned.
126 double stuck_refine_gradation = 2.0;
127 // Force-split: when the max energy stalls, split each worst cell's longest edge
128 // once, bypassing the split length gate. This unsticks a sliver whose edges are
129 // too short to be split-eligible, WITHOUT touching the sizing field (which the
130 // *factor ratchet above still drives). Adds at most one split per worst cell per
131 // stall, so it does not bloat the element count.
132 //
133 // This deliberately applies to EVERY worst cell, including one already at its target
134 // size. There used to be a stuck_refine_force_split_oversized_only gate that skipped
135 // those, on the argument that AMIPS is scale invariant so subdividing a badly shaped
136 // cell yields two badly shaped cells. The argument is sound about the cell itself and
137 // wrong about the outcome: force-splitting it also refines its NEIGHBOURHOOD, and that
138 // is what breaks a deadlocked configuration open. On Thingi10K 46024 -- the one model of
139 // 10,000 in the sweep that finished above stop_energy -- the gate refused ~2000 tets on
140 // every stall, the max energy froze at iteration 3 and stayed identical to 15 significant
141 // figures for the remaining 77 iterations (4.6 h). Without the gate the same model
142 // converges to 9.98 in 14 iterations and 11 minutes.
143 bool stuck_refine_force_split = true;
144
145
146 // ---- Skip good regions ----------------------------------------------
147 // Only smooth vertices incident to a cell whose energy is >=
148 // skip_good_regions_margin * stop_energy. Smoothing a vertex surrounded by
149 // good cells does nothing, so skipping it is free (14-16x faster smooth
150 // passes). Only smoothing is gated: gating the topology/sizing ops
151 // (split/collapse/swap) starves the optimizer and blows up the element
152 // count, so those always run over the whole mesh.
153 bool skip_good_regions = false;
154 // Safety margin on the "active" threshold: a cell is active when its energy is >= this
155 // fraction of stop_energy, so vertices near cells sitting just below the target are
156 // still smoothed.
157 double skip_good_regions_margin = 0.9;
158
159 double splitting_l2 = -1.; // the lower bound length (squared) for edge split
160 double collapsing_l2 =
161 std::numeric_limits<double>::max(); // the upper bound length (squared) for edge collapse
162
163 double stop_energy = 100;
164
171 double w_amips = 1e-4;
173 std::string smoothing_mode = "projected";
178
184 double w_envelope = 1. - 1e-4; // derived; not read from json
185
188 bool interleaved_smoothing = true;
189 int interleaved_smoothing_passes = 1;
190
191 // ---- Coarsening pass -------------------------------------------------
213 bool coarsen_pass = false;
237 bool coarsen_unbounded = true;
321
322 bool debug_output = false;
323 bool perform_sanity_checks = false;
324
332 void init_lengths_from_diagonal(const double diag)
333 {
334 diag_l = diag;
335 if (l > 0) {
336 lr = l / diag_l;
337 } else {
338 l = lr * diag_l;
339 }
340 splitting_l2 = l * l * (16 / 9.);
341 collapsing_l2 = l * l * (16 / 25.);
342
343 if (eps > 0) {
344 epsr = eps / diag_l;
345 } else {
346 eps = epsr * diag_l;
347 }
348
349 logger().info("PARAMS: eps = {}, l = {}", eps, l);
350 }
351};
352
353} // namespace wmtk
The parameters tetwild, triwild and simwild all share.
Definition OptimizerParameters.h:29
int project_line_search_nested_steps
Partial-projection bisections tried after it gives up; 0 disables that pass.
Definition OptimizerParameters.h:177
double w_amips
Definition OptimizerParameters.h:171
int coarsen_max_inner_passes
Definition OptimizerParameters.h:320
std::string smoothing_mode
"projected" or "exact"; see SmoothVertexOptions::SmoothingMode.
Definition OptimizerParameters.h:173
bool coarsen_pass
Definition OptimizerParameters.h:213
bool optimize_envelope_around_simplified
Definition OptimizerParameters.h:64
int coarsen_global_smoothing_passes
Definition OptimizerParameters.h:278
int coarsen_max_rounds
Definition OptimizerParameters.h:302
void init_lengths_from_diagonal(const double diag)
Derive the edge-length and envelope quantities from the bounding-box diagonal.
Definition OptimizerParameters.h:332
bool coarsen_unbounded
Definition OptimizerParameters.h:237
int split_high_valence_threshold
Definition OptimizerParameters.h:71
int coarsen_local_smoothing_passes
Definition OptimizerParameters.h:255
int project_line_search_steps
Bisections tried before the projected search gives up. See SmoothVertexOptions.
Definition OptimizerParameters.h:175
int coarsen_smooth_ring
Definition OptimizerParameters.h:271
bool smooth_quality_veto
Definition OptimizerParameters.h:183
int num_smoothing_passes
Number and placement of smoothing passes in the shared Wild optimization driver.
Definition OptimizerParameters.h:187