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