Wildmeshing Toolkit
Loading...
Searching...
No Matches
Functions
simwild.polyfem_ops.minimum_separation Namespace Reference

Functions

None step_run_polyfem (str polyfem_bin, dict sep_json, Path sep_json_path, Path sim_out_dir, dict cfg)
 
None step_run_polyfem_stiffness (str polyfem_bin, dict sep_json, Path sep_json_path, Path sim_out_dir, dict cfg)
 
tuple[list, list] _normalize_collision_pairs (list raw_pairs)
 
None run (dict cfg, out_dir=None)
 
 main ()
 

Detailed Description

minimum_separation — push collision bodies apart to a target separation
(AMIPS + fitting + Laplacian + GCP contact). Two outer-loop strategies via
cfg["strategy"]: "dhat" (default) ramps dhat multiplicatively from the
measured geometric gap (next dhat = dhat_growth * active) at fixed barrier
stiffness, binary-searching on overshoot; "stiffness" (experimental) pins
dhat at sep*(1+rtol) and raises the barrier stiffness until the separation
clears sep.

cfg reference: see spec.json here and the simwild.minimum_separation op.
Selections use the region/filter format from simwild.polyfem_ops.mesh_core.

Usage: python -m simwild.polyfem_ops.minimum_separation config.json

Function Documentation

◆ _normalize_collision_pairs()

tuple[list, list] simwild.polyfem_ops.minimum_separation._normalize_collision_pairs ( list  raw_pairs)
protected
Turn cfg["collision_pairs"] ([[side_A, side_B], ...], sides per
mesh_core.normalize_selection) into (unique_selections, polyfem_pairs).
Identical selections are deduped to one collision body; duplicate id
pairs collapse.

◆ run()

None simwild.polyfem_ops.minimum_separation.run ( dict  cfg,
  out_dir = None 
)
Run the full minimum-separation pipeline: extract interface
constraints, reduce the mesh for polyfem, iterate the dhat line-search
solve, and write the deformed mesh. See the module docstring for cfg
fields. Writes the generated polyfem inputs (separation.json, constraint
hdf5s, collision proxy, reduced mesh) to out_dir/sep_input, polyfem
outputs (logs, solution.txt) to out_dir/sep_output, and the deformed
mesh to output_msh (default <stem>_separated.msh); out_dir defaults to
the mesh's folder.

◆ step_run_polyfem()

None simwild.polyfem_ops.minimum_separation.step_run_polyfem ( str  polyfem_bin,
dict  sep_json,
Path  sep_json_path,
Path  sim_out_dir,
dict  cfg 
)
Iterate polyfem solves, ramping dhat until `sep` is reached: each
solve's "active distance" is parsed from stdout; undershoot commits the
state (warm start) and sets the next dhat to dhat_growth * active
(default 1.9 — the measured gap then sits at x = active/dhat ~ 0.53,
i.e. on the exact (4/3)(1-x)^3 outer branch of the GCP barrier, and the
gap grows multiplicatively); overshoot rolls back and halves the step
(binary search between the last undershoot dhat and the overshooting
one). The smallest overshooting dhat is kept as a bracket upper bound:
later undershoots bisect toward it instead of letting the growth rule
jump past a dhat already known to overshoot. Unless cfg["init_dhat"] is given, the initial gap is measured by
a zero-stiffness probe solve (nothing moves; polyfem reports the gap as
"active distance") and the ramp starts at growth*gap0, with the
overshoot line search anchored at gap0 (where the barrier exerts no
force). Fixed-stiffness ceiling (progress stalls because the penalties
balance the barrier) is warned about once. Mutates sep_json per
iteration, logs each solve to sim_out_dir/polyfem_iter_<i>.log, and
leaves the accepted solve's solution.txt for the caller. Raises
RuntimeError if a solve fails.

◆ step_run_polyfem_stiffness()

None simwild.polyfem_ops.minimum_separation.step_run_polyfem_stiffness ( str  polyfem_bin,
dict  sep_json,
Path  sep_json_path,
Path  sim_out_dir,
dict  cfg 
)
strategy="stiffness": pin dhat at sep*(1+rtol) and raise the barrier
stiffness kappa until the active distance clears sep. The contact force
vanishes at distances >= dhat, so the equilibrium can never exceed dhat —
the rtol overshoot bound holds by construction and no rollback is needed
(raising kappa only pushes the distance up, monotonically).

Update rule: near dhat the barrier force scales like
kappa * (dhat - d)^2 / dhat, and the penalty force resisting it is
locally ~constant, so the deficit delta = dhat - active follows
delta ~ kappa^(-1/2). Each iteration solves that power law for the kappa
that lands at half the tolerance band (delta = (dhat - sep)/2); once two
solves exist the exponent is re-fit from them in log-log (the GCP
potential may not vanish exactly quadratically at dhat). The multiplier
is clamped to max_stiffness_multiplier per step to protect Newton
conditioning. Same warm-start/state/log conventions as
step_run_polyfem.