Skip to content

Add runnable tensegrity simulation demos (MuJoCo, PyBullet, PyChrono, Newton, DiffPD, PolyFEM+IPC) + 3D animated renders + Edison survey + regime-aware sweeps + PLA/TPU 85A printable-design model + BO integration bridge + PR #35 Sobol T3-prism sweep ac... - #33

Open
sgbaird-alt with Copilot wants to merge 53 commits into
mainfrom
copilot/explore-simulations-for-tensegrity
Open

Conversation

Copilot AI commented May 8, 2026

Copy link
Copy Markdown
Contributor
  • Fetch Edison sim survey + drive both regimes
  • PLA strut + TPU 85A printable-design model + class-1 check + sweep
  • Newton (Warp) mid-fidelity drop with tendons in load path
  • DiffPD source build + cube drop (Edison Rec B)
  • PolyFEM source build + cube drop (Edison Rec A)
  • 3D animated GIF/MP4 renders (mujoco) with strain-coloured tendons
  • T-prism mesher (simulations/tprism_mesh.py): 3 PLA struts + 9 TPU 85A tendons fused via gmsh OCC fragment
  • simulations/polyfem_drop.py --geometry tprism JSON builder + CLI dispatch
  • PolyFEM rebuild (~25 min) and run prism drop end-to-end (124bba2)
  • Address PR #4427965775 / #4462016260 — crutch + NASA still going beyond floor
    • Drop the SUPERball-style "payload suspended inside cage" architecture (oscillated wildly with TPU-85A stiffness, prism flipped through floor on impact)
    • Distribute viz payload mass across the 3 struts (axial-load model — matches the working 1m baseline drop and matches a real crutch tip loaded through the strut tip)
    • Stiffen floor + strut contact (solref="0.002 1", solimp="0.98 0.999 0.0001")
    • Cap viz payload to what the cell can statically cradle (≤5% cable stretch); crutch viz now 0.5 kg (actual 75 kg labelled in title), NASA stays at 5 kg
    • Verified: min strut-bottom-z ≈ −1.3 mm (crutch) / −2.7 mm (lander) — invisible at cell scale (was −28 mm / −22 mm before)
  • Address PR comment 4462510090 — switch strut material PETG → PLA per Edison query on strut material (PLA vs PETG vs HF/CF) — fetched + interpreted #45 across simulation constants, comments, and READMEs (printable_design.py primary PLA Material with PETG kept as a backward-compat alias; tprism_mesh.py physical-volume group renamed PETG_strutPLA_strut; polyfem_drop.py NeoHookean kwargs renamed *_petg**_pla* with PLA defaults E=3.5 GPa, ν=0.36, ρ=1240; updates in newton_drop.py, printable_sweep.py, render_regimes.py, regimes.py, simulations/README.md)
  • Address comment 4500576843 — Edison LITERATURE_HIGH task 78fb09a2 modeling-feedback contacts brief committed at edison-trajectories/modeling-feedback-contacts/ (6dae17f)
  • Address comment 4500578897simulations/validation_experiments.md: 10-row bench-test table mapping each Instron/drop-tower experiment to a specific simulation output, plus a 3-test minimum-viable validation budget for the T3 prints we already have (Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35)
  • Address comment 4500584002simulations/bo_integration.md + simulations/bo_evaluator.py: drop-in replacement for PR Scaffold Bayesian-optimization script with honegumi + customized tensegrity campaign #30 simulate_specimen that maps Ax parameterization → PrintableDesign → overridden Regimerun_regimes.simulate(...){F_peak_N, SEA_J_per_g, eta}; forward-compatible fidelity={"C","B","A"} signature for the three-tier ladder (MuJoCo / Newton / PolyFEM+IPC) from Edison sim survey 782657e0
  • Address comment 4500844340bo_evaluator._t3_seed_designs() returns the three PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 T3-prism prints (scale 1.0× / 1.5× / soft-tendon variant) as Ax-compatible dicts so the BO loop's first batch reflects parts already on the bench; other PR Scaffold Bayesian-optimization script with honegumi + customized tensegrity campaign #30 topologies (truncated-octa, simplex-4-strut, stacked-prism) emit a warning and fall back to T3 physics until the generic mesher lands
  • Address comment 4663414812 — simulation cost, PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 BO integration, and Edison analysis query
  • Address comment 4664686033 — tier B/A fidelity clarification + multi-task BO recommendation: new ## Multi-task treatment of the regimes section in simulations/bo_integration.md recommends a multi-task GP (MTBO) that carries the regime as a task and shares information across the crutch/lander campaigns (replacing the prior one-campaign-per-regime suggestion), with the Ax Specified_Task_ST_MTGP_trans / BOTORCH_MODULAR wiring from the Honegumi multitask tutorial, the mean-collapse caveat from the Honegumi concept page, a note that fidelity (C/B/A) generalizes as a second task axis, and updated open-questions
  • Address comment 4686442352 — re-ran every simulation type from a fresh environment and committed the refreshed simulations/outputs/
    • MuJoCo tier-C: mujoco_drop (37.2 g), mujoco_sweep, run_regimes (crutch k*=5798/16.3 g, lander k*=400/103.9 g), printable_sweep, benchmark_costs (~107 ms/design on this runner's AMD EPYC 9V74)
    • PyBullet drop (peak KE 0.95 J); PyChrono drop via conda (peak KE 1.01 J)
    • Newton/Warp XPBD drop + tendon sweep on CPU: 3003 / 6346 / 13165 g at d_t 1.5 / 3.0 / 5.0 mm
    • gmsh T-prism mesher (2168 nodes / 5481 tets, 15 PLA + 9 TPU volumes)
    • OSMesa renders: render_spotchecks, render_mujoco_drop, render_regimes
    • DiffPD built from source (swig + cmake) + cube drop (peak 61.2 g, settled 15.0 mm)
    • PolyFEM+IPC built from source (~30 min, 161 MB binary) + cube drop (0.9 g) + welded PLA/TPU T-prism drop (1.0 g, settled 29.66 mm)
    • Added simulations/outputs_bundle.zip (11 MB, < 100 MB so no split needed) archiving the full simulations/outputs/ set
  • Address comment 4686953016 — run many PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 T3-prism Sobol variations through the simulators and analyse the results
  • Address comment 4687620375 — extend the Sobol T3-prism campaign beyond Tier-C/Tier-B to the full C→B→A ladder across 5 engines, using parallel background builds to fit Tier-A inside the window
    • Started the ~33 min PolyFEM+IPC source build (161 MB binary) in a detached background process and built/installed the rest in parallel (MuJoCo, Newton, PyBullet, DiffPD, PyChrono-via-conda) while running the fast sims; Sobol set drawn with scipy.stats.qmc.Sobol (Ax not required, per the comment)
    • Tier-A PolyFEM+IPC added to sobol_t3_campaign.py (run_tier_a + _tier_a_one multiprocessing worker, 2 concurrent processes) — welded PLA/TPU T-prism drops on an 8-design subset; mesh resolution scaled with cross-section (lc_strut/lc_tendon) to hold tet count ~6k; meshes written outside run_drop's work_dir (which it wipes on entry)
    • Added two more Tier-C rigid engines to the campaign: PyBullet (32 designs) and PyChrono (16, run via a conda-env subprocess --param-json bridge); added parameterized run_param() to pybullet_drop.py and pychrono_drop.py (+ --param-json stdin/stdout CLI for the conda interpreter)
    • Extended analyse() with an engine-ladder Spearman comparison (sobol_t3_engine_ladder.png) and a Tier-A figure (sobol_t3_tierA.png); rewrote the cross-fidelity report section as a C→B→A ladder; new CLI args --n-tiera, --n-pybullet, --n-pychrono, --tiera-workers
    • Engine-ladder Spearman ρ vs Tier-C MuJoCo lander F_peak: PyChrono +0.70, Newton +0.60, PolyFEM +0.43, PyBullet ≈ −0.02 (bare-prism peak is contact-dominated/design-invariant — reported honestly, not weighted); Tier-A peak-g is ~1 g (settles below the IPC dhat envelope) so settled-COM height (68–112 mm) is its discriminating observable
    • New outputs (sobol_t3_tierA.csv, sobol_t3_pybullet.csv, sobol_t3_pychrono.csv, sobol_t3_tierA.png, sobol_t3_engine_ladder.png), refreshed sobol_t3_analysis.md, README, and outputs_bundle.zip (11.8 MB)
    • Scope note: DiffPD remains a material-only soft-cube smoke test (it can't ingest the prism geometry without a generic soft-body mesher), so it is not part of the geometry-varying Sobol sweep
  • Address comment 4700384140 — violin plots (with jittered raw points) of the Sobol T3-prism measurements
    • New simulations/sobol_t3_violins.py: reads the existing outputs/sobol_t3_*.csv campaign measurements and renders plotly.express.violin(..., points="all", box=True) with non-zero jitter so every raw measurement is drawn as a jittered swarm beside each violin (PNG via kaleido + interactive HTML)
    • outputs/sobol_t3_violin_objectives.{png,html} — Tier-C MuJoCo objectives (F_peak, SEA, eta), one violin per regime, faceted with independent y-axes (512 feasible designs)
    • outputs/sobol_t3_violin_engines.{png,html} — per-engine peak deceleration (g) across the C→B→A ladder (PyBullet/PyChrono/Newton/PolyFEM) on a log y-axis
    • Documented the script in simulations/README.md, sobol_t3_analysis.md, and the campaign Files list; refreshed outputs_bundle.zip
  • Address comment 4713093337 — send the Sobol T3-prism campaign results (scripts, data, figures) + project context to Edison ANALYSIS, fetch, and report back
    • New scripts/edison/submit_sobol_t3_results.py + scripts/edison/fetch_sobol_t3_results.py: bundle the campaign scripts (sobol_t3_campaign.py, sobol_t3_violins.py, bo_evaluator.py, run_regimes.py), the measured CSVs (sobol_t3_tierC/tierB/tierA/pybullet/pychrono.csv), the figures (Pareto / sensitivity / Tier-C-vs-Tier-B / engine-ladder / Tier-A / both violin plots), the sobol_t3_analysis.md + bo_integration.md write-ups, and a project-context note as a single Edison data collection, submit ANALYSIS, poll, and commit the answer
    • Edison ANALYSIS task ff8faab3 (status success) committed at edison-trajectories/sobol-t3-results/ — Edison re-analysed the CSVs directly and confirmed our reproducible numbers (Tier-C F_peak near-invariant; SEA/eta discriminating; engine-ladder ρ PyChrono +0.70 / Newton +0.60 / PyBullet −0.02 / PolyFEM +0.43) while sharpening several claims we should revise: crutch Tier-C F_peak is essentially the static payload weight (ratio 1.002), Tier-C SEA is a conservative elastic-energy proxy (not true dissipation), PolyFEM peak-g is ~1 g flat (so Tier-A does not back the Tier-C F_peak ladder), and strut_d_mm's apparent leverage is largely a rigid-body mass/contact-geometry artifact (ρ=−0.976 vs an L·d² strut-mass proxy, sign flips by regime)
    • Recommendations captured in the committed brief: treat Tier-C as a biased cheap auxiliary (warm-start a low-fidelity surrogate only), promote 8–12 diverse/high-uncertainty designs to Tier-B/bench, fit a Kennedy–O'Hagan / recursive co-kriging discrepancy model, and run cost-aware constrained qNEHVI with regime+fidelity as task labels; first print batch should be information-maximising (strut_d/H extremes + matched twist pairs + replicates), with priority ablations (base-reaction-force vs payload-accel F_peak, filtered/unfiltered peaks, constant-mass strut-diameter sweep, twist-injection plumbing audit at Tier-C/Tier-B) and a full multi-fidelity BO citation list
  • Address comment 4756521145 ("carry on") — implement the priority artifact-vs-physics ablations Edison's ff8faab3 review recommended, in new simulations/sobol_t3_diagnostics.py (run on 48 feasible PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 designs)
    • Base reaction force vs payload acceleration — re-measure the vertical floor-reaction force (sum of strut↔floor contact forces via mj_contactForce, the sensorized-platen observable): genuine ~104× static-weight transient for the lander while the crutch's large soft cell barely loads the floor in the 25 ms window, confirming the payload-accel F_peak is a support-load proxy not an impact peak → outputs/sobol_t3_diag_base_reaction.csv
    • CFC-180 on vs off — lander raw F_peak span (~10%) is ~3× the filtered span (~3%), so the filter suppresses part of the design transient (the fix is the observable, not removing the filter) → outputs/sobol_t3_diag_cfc.csv
    • Constant-mass strut-diameter sweep — holding strut mass fixed (PLA density ∝ 1/d²) shrinks the lander strut_d effect ~17×, confirming Edison's L·d² inertia/contact confound; reported as effect-size (peak-g range) since Spearman stays ≈±1 on a monotonic sweep → outputs/sobol_t3_diag_constmass.csv
    • Twist plumbing audit — geometry shifts ~20 mm across 40–80° twist when supplied, but regimes.Regime has no twist field and run_regimes.build_xml never passes it, so the twist≈0 Tier-C result is un-consumed plumbing not physical irrelevance
    • 3-panel summary figure outputs/sobol_t3_diagnostics.png + write-up simulations/sobol_t3_diagnostics.md; narrowed the matching over-claims in sobol_t3_analysis.md (payload-accel F_peak relabeled support-load proxy; strut_d demoted from "dominant lever" to inertia confound; twist framed as plumbing); documented the script in simulations/README.md; refreshed outputs_bundle.zip
  • Address comment 4759514616 — run a closed-loop Bayesian-optimization campaign using only simulations as the objective functions, mirroring PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 but with simulations instead of real experiments
  • Address comment 4759900555 — rework the sim-only BO plots so the optimization behavior is legible per regime, per seed, and per tier method, with predictive-signal diagnostics
    • Separated regimes onto independent figures — every figure now belongs to a single (tier, regime) pair so crutch and lander never share an axis (the prior shared plots were unreadable given their ~6× objective-scale gap)
    • Individual per-seed plotsoutputs/sim_bo_<tier>_<regime>_seed<k>_{convergence,pareto,cv}.png
    • Std-dev bands on the averaged-behavior plotsoutputs/sim_bo_<tier>_<regime>_convergence.png plots the mean running-best with a ±1σ band across seeds (faint per-seed traces behind it)
    • Repeated across tier methods — rewrote simulations/sim_bo_campaign.py into a tier/seed-parameterized closed-loop driver (--tiers C B, --seeds, --n-iter, --regime, --raw-peak, --outdir): Tier-C MuJoCo runs the 3-objective qNEHVI loop while Tier-B Newton/Warp XPBD runs a single-objective F_peak loop (Newton only exposes the payload-accel trace). Headline cross-tier result: Tier-C F_peak is near-flat (support-load proxy) but Tier-B F_peak spans ~2.5× and the BO genuinely descends because the elastic tendons sit in the dynamic load path
    • LOO-CV plots per seed and modeloutputs/sim_bo_<tier>_<regime>_seed<k>_cv.png via Ax's built-in cross_validate (refit Generators.BOTORCH_MODULAR adapter), showing strong predictive signal where it matters (Tier-C crutch SEA R²≈0.97/ρ≈0.96, Tier-B F_peak R²≈0.99); near-flat CV outcomes (e.g. Tier-C lander eta) are pinned observables, not model failures
    • Ran full Tier-C (3 seeds × both regimes) and Tier-B Newton (2 seeds × both regimes) campaigns; replaced the old single-layout outputs (sim_bo_{crutch,lander}.csv, sim_bo_{pareto,convergence}.png) with tier-named CSVs (sim_bo_<tier>_<regime>.csv + _pareto.csv) and the per-seed/aggregate figures; rewrote simulations/sim_bo_campaign.md, updated simulations/README.md, and refreshed outputs_bundle.zip
    • Scope note: Tier-A (PolyFEM) is intentionally left out of the closed loop (expensive, single geometry-only observable) and flagged as future work
  • Address comment 4759775185 / 4760735518 — send the sim-only BO figures/data to Edison ANALYSIS for mock-reviewer feedback, fetch, report back, and implement the follow-up recommendations (the prior session timed out before reporting back)
    • New scripts/edison/submit_sim_bo_review.py + scripts/edison/fetch_sim_bo_review.py: bundle the campaign driver (sim_bo_campaign.py), the sim→BO bridge (bo_evaluator.py), the per-(tier,regime) trial + Pareto CSVs, and the per-seed/aggregate convergence, Pareto, and LOO-CV figures, plus sim_bo_campaign.md/bo_integration.md and a project-context note, as a single Edison collection; submit ANALYSIS, poll, and commit the answer
    • Edison ANALYSIS task 491f90ae (status success) committed at edison-trajectories/sim-bo-review/ — confirms real predictive signal on the discriminating outcomes (Tier-C crutch SEA, Tier-B F_peak) and that weak CV on near-constant outcomes (Tier-C lander eta) is intrinsic, not model failure; flags Tier-B was regime-blind (matched crutch/lander F_peak ratio 0.998), that the per-fidelity constraints don't align (Tier-C 100% feasible / Tier-B 0%), Tier-C lander BO proposal collapse, and recommends a contextual, cost-aware, discrepancy-aware multi-fidelity BO (regime + fidelity as task/context, physics features, Kennedy–O'Hagan / co-kriging fusion, peak-g as the constraint variable, constrained qNEHVI)
    • Fixed the Tier-B regime-plumbing artifact in simulations/sim_bo_campaign.py: _eval_tier_b now seeds each Newton drop with the regime's own impact velocity (crutch 1.4 m/s, lander 9.8 m/s) via newton_drop.build_model(impact_velocity_mps=…) and reads a robust start-up-gated peak (newton_drop.peak_decel_g), so crutch and lander are now physically distinct (e.g. ~1463 N vs ~564 N for the same seed design instead of the prior 0.998 ratio)
    • Added range-normalized CV diagnostics (nrmse = RMSE/(max−min) and a constant-mean null_skill baseline) to every per-(tier,regime) outputs/sim_bo_<tier>_<regime>_cv_summary.csv, per Edison rec. B, so a high on a near-constant outcome is not mistaken for decision-useful signal
    • Refreshed the regime-aware Tier-B simulations/outputs/ (CSVs + figures) and synced simulations/sim_bo_campaign.md (Tier-B narrative + numbers, LOO-CV table, Files list) to the new regime-distinct results, which the output refresh had made stale
  • Address comment 4760877672 — find the actual Tier-C Pareto front over the PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 box and render the best/worst/mediocre designs as callouts (sims are cheap enough that no cost-aware/multi-fidelity loop is needed)
    • New simulations/pareto_render_campaign.py: densely Sobol-maps 2048 designs per regime over the exact PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 box and scores each at Tier-C MuJoCo (bo_evaluator.evaluate_design, CFC-180 filtered) on the three objectives (minimize F_peak_N, maximize SEA_J_per_g, maximize eta) at ~0.15 s/eval; takes the 3-objective non-dominated set as the empirical Pareto front
    • Selects representative designs — Pareto winners (max-SEA, max-eta, balanced knee, min-F_peak), 2 worst dominated, and 2 mediocre mid-rank — and renders each as a 3-D MuJoCo still (geometry + strain-coloured tendons via an overridden Regime), plus headline best/worst drop GIF/MP4 animations per regime
    • Annotated outputs/pareto_<regime>_annotated.png: a SEA↔eta Pareto scatter (colour = near-invariant F_peak) with the render stills dropped on as callout thumbnails + leader lines, and a clean 2-D SEA↔eta frontier staircase rather than the zig-zagging 3-objective set
    • Outputs: pareto_<regime>.csv (2048 rows + feasible/pareto flags), per-pick stills pareto_<regime>_render_<tag>.png, pareto_<regime>_{best,worst}_drop.{gif,mp4}, and pareto_summary.md; both regimes report the whole box printable, F_peak span ~3–4 % (crutch 712–739 N, lander 4628–4790 N), SEA↔eta the live trade-off (best cells short/fat-strut/large-radius, worst tall/slender)
    • Honest caveats carried over: Tier-C F_peak is a support-load proxy (shown as colour), SEA is an elastic-energy proxy, and twist_deg≈0 at Tier-C is un-consumed plumbing; write-up simulations/pareto_render_campaign.md + README.md entry; refreshed outputs_bundle.zip (~25 MB)
  • Address comment 4760939061 — assess whether the objective evaluations are "fair" w.r.t. mass / volume / contact area (especially for the lander) and send the thinking to Edison for mock feedback
    • New simulations/fair_evaluation_analysis.md: quantifies the size confound — across the PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 box the cell mass varies 6.2× (9.5→59 g), envelope volume 4.7× (118→553 cm³), and strut-tip footprint 4.0× (85→339 mm²), so designs are compared at very different sizes; only SEA_J_per_g controls for mass, none control for volume/footprint, and the lander F_peak is a real ~94–98 g transient (only the crutch F_peak is a support-load proxy)
    • Documents the real scaled-up lander-module constraints (hard mass budget ≈2–5 % of landed mass → ~100–250 g for the 5 kg regime; stowed/deployed envelope volume; footprint/ground-pressure as a cap and a floor; crush stroke with physics floor s ≥ v²/2a_max ≈ 3.3 mm) and lays out two routes to fairness — (A) re-parameterize onto a constant-mass / scale-free shape-ratio manifold so budgets hold by construction, vs (B) keep the box but score intensive objectives (SEA_J_per_g + SEA_J_per_cm³, base-reaction peak-g, ground pressure) with mass/volume/footprint + peak-g as Ax outcome constraints under constrained qNEHVI — plus a recommended hybrid for the lander
    • New scripts/edison/submit_fair_evaluation.py + scripts/edison/fetch_fair_evaluation.py; README entry
    • Edison ANALYSIS task e43abed6 (status success) committed at edison-trajectories/fair-evaluation/ — endorses the diagnosis and the hybrid, independently reproduces the confound (~6.6× mass / 4.69× volume / 4.0× footprint), and sharpens the write-up: re-parameterization (constant-mass equality manifold + dimensionless Buckingham-π shape groups) is sounder than outcome constraints for the binding mass budget; don't hard-constrain a biased cheap observable (use Tier-C base reaction only for coarse screening, reserve peak-g acceptance for Tier-B/A/bench); report fronts at 2–3 fixed mass/envelope budgets; corrected the over-claim that lander F_peak ≈ static load and reframed GEVS/HAVS as requirement proxies — all folded back into fair_evaluation_analysis.md
    • Scope note: the constant-mass-manifold re-parameterization and constrained-qNEHVI wiring are listed as prioritized follow-on changes; this comment's deliverable is the analysis + the Edison mock review
  • Address comment 4815289639 — clarify that "hybrid" means combining Route A + Route B inside a single AxClient campaign per regime (not two separate campaigns); added a clarifying paragraph under "Recommended hybrid" in simulations/fair_evaluation_analysis.md (cbcf27b)
  • Address comment 4815305004 — update the BO script(s) to implement the hybrid (Route A constant-mass manifold + Route B intensive objectives/outcome constraints in one campaign per regime)
    • Extended simulations/bo_evaluator.py with the hybrid geometry/manifold machinery: cell_geometry_metrics() (cell mass / envelope volume / strut-tip footprint, all derived from PrintableDesign.nodes — also fixes a pre-existing strut-length bug by using design.strut_length_m); design_from_shape_ratios() — the Route A constant-mass manifold that builds a cell from four dimensionless ratios (H/R, H/strut_d, cable_d/strut_d, twist) and solves the single overall scale by closed-form cube root so cell mass equals m* exactly; the inverse design_to_shape_ratios(); and base_reaction_peak_N() — the Route B base floor-reaction observable (sums vertical strut↔floor contact forces, optionally CFC-180 filtered)
    • Refactored the Tier-C sim core into evaluate_printable_design(design, *, regime, fidelity, cfc180, base_reaction) (called by evaluate_design) and extended the return dict with cell_mass_g, envelope_cm3, footprint_mm2, SEA_J_per_cm3, and optional F_base_peak_N; all existing keys (F_peak_N, SEA_J_per_g, eta) and behaviour preserved for backward compatibility
    • New simulations/sim_bo_hybrid_campaign.py: the fair closed-loop analogue of sim_bo_campaign.py — one AxClient constrained-qNEHVI campaign per regime over the four scale-free shape ratios at a fixed cell mass m* (Route A), scoring intensive objectives (impact F — base floor-reaction for the lander, payload-accel F_peak for the crutch's large soft cell —, SEA_J_per_g, SEA_J_per_cm³, eta) under envelope-volume + strut-tip-footprint Ax outcome constraints (Route B; mass is structurally fixed so it is not a constraint); seeded with the three printed PR Add T3-prism (3-strut tensegrity) parametric CAD with Bambu PETG .gcode.3mf slice + re-importable project .3mf (H2D-only, supports enabled, scale 1.5× / cable_d 4.5 mm) + PLA-cables and PLA-struts/TPU-cables MM variants (with modeled-in PLA scaffo... #35 T3 cells projected onto the manifold; per-seed + mean±σ convergence, intensive-trade Pareto, constraint-feasibility, and LOO-CV figures; CLI --regime/--seeds/--n-iter/--mass-g/--envelope-max-cm3/--footprint-min-mm2/--footprint-max-mm2/--raw-peak/--outdir
    • Verified end-to-end on both regimes (constant-mass round-trip exact; crutch payload-accel channel and lander base-reaction channel; constrained qNEHVI + LOO-CV run cleanly); updated fair_evaluation_analysis.md §4 (steps 1–4 marked implemented, pointing at the new helpers/script) and simulations/README.md
    • Follow-on: commit a full multi-seed outputs/ artifact set and a dedicated simulations/sim_bo_hybrid_campaign.md write-up (the 4-objective constrained-qNEHVI run is slow; the module docstring documents usage and the output files in the meantime), and re-run the dense Pareto render campaign on the constant-mass manifold (fair_evaluation_analysis.md §4 step 5)

Copilot AI changed the title [WIP] Begin exploring state-of-the-art simulations for tensegrity structures Add runnable tensegrity simulation demos (MuJoCo, PyBullet, PyChrono) + Edison survey May 8, 2026
Copilot AI requested a review from sgbaird-alt May 8, 2026 17:30
@sgbaird-alt

Copy link
Copy Markdown
Collaborator

@copilot fetch edison results. Extensively consider #28 and #18 in terms of the choices of simulations and parameters (e.g., forces/loads/timescales/etc.). This doesn't preclude other applications like the ones mentioned in #14 and #16 ; provide recommendations and try things out from both regimes.

Re-run additional simulations based on this. Embed visualizations from those simulations directly in your comment reply.

@sgbaird-alt

Copy link
Copy Markdown
Collaborator

@copilot consider also the fact that we might be using PETG struts + TPU "strings" as a tensegrity-like structure, and how we might best design and model that in a way that helps us mimic a true tensegrity structure if were to make one manually.

…) and commit Edison survey

Agent-Logs-Url: https://github.com/vertical-cloud-lab/tensegrity-optimization/sessions/bfc9f985-512f-4973-b7a2-c04715c29984

Co-authored-by: sgbaird-alt <71569943+sgbaird-alt@users.noreply.github.com>

Copilot AI commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fetch edison results. Extensively consider #28 and #18 in terms of the choices of simulations and parameters (e.g., forces/loads/timescales/etc.). This doesn't preclude other ...

Edison 782657e0-0818-4755-9e18-60c8039b2ccd finished success and is committed at edison-trajectories/2026-05-08-sim-survey-782657e0.{md,json}. Its core recommendation is a three-tier multi-fidelity stack: (A) PolyFEM+IPC differentiable FEM for high-fidelity contact, (B) DiffPD for fast differentiable mid-fidelity sampling, (C) NTRT/MuJoCo rigid-strut + tendon for cheap topology screening — with the explicit caveat that tier C "cables may lack contact modeling… energy absorption predictions will be unreliable without higher-fidelity refinement."

I encoded the two application regimes in simulations/regimes.py, both clamped to the Lansmont M23 envelope from #28 (≤ 5,000 g, ≥ 0.25 ms half-sine, ΔV ≤ 9.8 m/s, ≤ 36 kg payload):

regime source payload ΔV cell target peak target pulse
crutch_tip #18 + tasks 39708fbc/9832f01a/f21cf79c/7a21d00e 75 kg 1.4 m/s (≈ 0.10 m drop) Ø24 mm × 25 mm ≤ 8 g (HAVS) ≥ 5 ms
nasa_lander #14, #16 (SUPERball, MER airbag, GSFC GEVS) 5 kg 9.8 m/s (M23 max ΔV) Ø200 mm × 200 mm ≤ 1500 g (GEVS) ≥ 0.5 ms

simulations/run_regimes.py then drives the MuJoCo prism through both regimes — three illustrative cable stiffnesses for the time-history figure, and an 11-point ~3-decade geometric sweep for the BO-objective figure.

Crutch-tip regime (#18) — payload accel / vertical velocity / tendon strain energy vs. time, then a stiffness sweep:

crutch time series
crutch sweep

NASA lander / CubeSat regime (#14, #16) — same plots:

NASA time series
NASA sweep

regime best-fit k (N/m) peak (g) pulse (ms) SEA (J/kg)
crutch_tip 5,798 16.3 7.5 ~0
nasa_lander 5,060 102.8 7.9 0.06

NASA-lander 100 g / 8 ms comfortably clears the GEVS 1500 g target; crutch 16 g is ~2× the 8 g HAVS target. The most actionable finding from the sweeps is empirical confirmation of Edison's Rec C limitation: peak g is flat (±2 %) across three decades of cable stiffness because in a rigid-strut model the impulse is set by floor contact, not the cable network — but SEA varies ~10×. That motivates moving to Edison Rec B (DiffPD) before doing real crutch-design BO; I've left that as a follow-up checklist item rather than dragging this PR into a second engine. (commit ce1edba)

Copilot AI changed the title Add runnable tensegrity simulation demos (MuJoCo, PyBullet, PyChrono) + Edison survey Add runnable tensegrity simulation demos (MuJoCo, PyBullet, PyChrono) + Edison survey + regime-aware sweeps May 8, 2026

Copilot AI commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

@copilot consider also the fact that we might be using PETG struts + TPU "strings" as a tensegrity-like structure, and how we might best design and model that in a way that helps us mi...

Added a PETG strut + TPU 95A printable-design module that replaces the abstract cable stiffness k with the actual physical knobs an operator turns when fabricating one manually on the H2D, and that explicitly checks whether the resulting geometry is still a true (class-1) tensegrity.

simulations/printable_design.py — material model + class-1 check:

  • k = E_TPU · π·(d_t/2)² / L, with TPU 95A E ≈ 25 MPa (small-strain secant) and PETG E ≈ 2 GPa.
  • PrintableDesign.is_class_1 / class_1_margin_m compute the closest-approach distance between the three struts and flag designs where d_s ≥ d_min (the structure becomes "tensegrity-like": loads bypass tendons through strut-strut contact, BO objective stops reflecting design intent). Crutch margin 10.9 mm, lander margin 103 mm — both regime defaults pass.
  • Bambu H2D printability bounds baked in: tendon Ø ∈ [1.2, 6.0] mm (3-perimeter rule at 0.4 mm nozzle ↔ switch to multi-strand), strut Ø ≥ 2.0 mm, prestrain capped by TPU break stress.

simulations/printable_sweep.py — 7 × 5 grid over (tendon Ø, prestrain) for each regime, with cable stiffness derived from the printable design every iteration. Peak |a| (g) and SEA (J/kg) heatmaps:

crutch printable heatmap
NASA printable heatmap

Pareto clouds (peak vs SEA, marker colour = tendon Ø, marker size ∝ prestrain, red dashed = regime peak target):

crutch printable pareto
NASA printable pareto

Regime Best class-1 design (peak ≤ target, max SEA)
nasa_lander d_t = 4.0 mm, prestrain 0 % → 92 g / 1.03 J/kg (under the 1500 g GEVS target); comfortably printable on H2D.
crutch_tip None — the entire printable k-range (1.1 – 28 kN/m at the 25 mm strut length) still leaves the rigid-prism floor-contact impulse > the 8 g HAVS target. Confirms in printable units the same Edison Rec C limitation: crutch design needs DiffPD/IPC fidelity, or a redesigned cell where a TPU shell carries the contact load instead of the rigid strut tips.

The CSV outputs include the class-1 flag column so a future BO loop can filter out non-tensegrity designs without re-running the geometry check. Two earlier comments from the code reviewer were minor nits; I addressed the meaningful one (2.0 * 0.5 * xx in the class-1 inequality) in 5031a67 and left the cosmetic ones (parens around r*2*1e3, table cell wrapping) alone to keep the change focused. (commits 8f36c3a, 5031a67)

Copilot AI changed the title Add runnable tensegrity simulation demos (MuJoCo, PyBullet, PyChrono) + Edison survey + regime-aware sweeps Add runnable tensegrity simulation demos (MuJoCo, PyBullet, PyChrono) + Edison survey + regime-aware sweeps + PETG/TPU printable-design model May 8, 2026
@sgbaird-yolo

Copy link
Copy Markdown
Collaborator

@copilot btw it's TPU 85A that we're using. Attempt running DiffPD and PolyFEM+IPC

Copilot AI commented May 9, 2026

Copy link
Copy Markdown
Contributor Author

@copilot btw it's TPU 85A that we're using. Attempt running DiffPD and PolyFEM+IPC

Done both.

TPU 85A propagated through printable_design.py, printable_sweep.py, and the README: Material("TPU85A", young_MPa=12.0, density_kgm3=1200.0, yield_break_MPa=26.0) (NinjaFlex-class, ~2× softer per unit cross-section than the 95A I had earlier). Sweep outputs regenerated; class-1 / printability constants unchanged.

DiffPD / PolyFEM+IPC attempts:

  • DiffPD (MIT GFX, SIGGRAPH 2021) is not on PyPI — only as a C++/Pangolin source repo whose CMake build needs OpenGL drivers that aren't on this runner.
  • PolyFEMpip install polyfempy fails with CMake Error: source directory does not appear to contain CMakeLists.txt (the PyPI sdist is incomplete). The maintained route is cloning polyfem/polyfem and building manually with Eigen + libigl + ipc-toolkit + suite-sparse — ~25 min build, ~6 GB disk, outside this sandbox's budget. Documented as a reproducer at the bottom of the README so the next pickup can resume cleanly.
  • Stand-in I did get running: NVIDIA Newton 1.1 (pip install newton, built on Warp). Newton is GPU-accelerated, multi-physics (rigid + particle + soft + cloth + MPM), differentiable via Warp autodiff tapes — the exact capability we wanted DiffPD for. New simulations/newton_drop.py builds the prism as an all-particle XPBD network with TPU-85A tendons (and 6 internal payload-suspension tendons in the SUPERball / NASA TBR style) so cables are physically in the impact load path:

newton drop
newton tendon sweep

Tendon Ø Newton peak |payload accel|
1.5 mm ~2,400 g
3.0 mm ~4,200 g
5.0 mm ~11,400 g

Versus the rigid-strut MuJoCo/PyBullet/PyChrono runs where peak g was floor-pinned flat ±2 % across three decades of cable stiffness, here peak g responds monotonically to TPU-85A tendon Ø — the BO objective is no longer degenerate. Absolute values are still high (the soft 12 MPa tendons let the payload free-fall deep before the suspension snaps taut, giving a rope-snap profile); two follow-ups left in the README are (i) add prestrain so suspension is taut at rest, (ii) replace the all-particle struts with rigid bodies via add_body + add_shape_capsule so PETG-spring numerics don't enter the integration. Both are mechanical refinements rather than tooling escalations — the key Tier-C → Tier-B step is delivered. (commit 065cc62)

Copilot AI changed the title Add runnable tensegrity simulation demos (MuJoCo, PyBullet, PyChrono) + Edison survey + regime-aware sweeps + PETG/TPU printable-design model Add runnable tensegrity simulation demos (MuJoCo, PyBullet, PyChrono, Newton) + Edison survey + regime-aware sweeps + PETG/TPU 85A printable-design model May 9, 2026

Copilot AI commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Not sure to what extent any of these are "fair" tasks. I.e., primarily in terms of mass, volume, and contact area.

@copilot suggest ways to make these evaluations for the different...

You're right that the current tasks aren't fair. Wrote up the thinking in simulations/fair_evaluation_analysis.md and sent it to Edison ANALYSIS for mock feedback (commit 19df1ac).

The core problem (quantified): every corner of the PR #35 box is a different-sized object. Sweeping it gives 6.2× cell mass (9.5→59 g), 4.7× envelope volume (118→553 cm³), and 4.0× strut-tip footprint (85→339 mm²). So "fat/short/large-radius wins on SEA" is partly a tautology — those cells just have more material/volume/contact area. Of the three objectives only SEA_J_per_g controls for mass; none control for volume or footprint; and the lander F_peak is a real ~94–98 g transient but base reaction is the better observable. The crutch tolerates this (loose envelope); for the lander, mass and volume are binding budgets, so letting the optimizer "win by getting bigger" is a problem-definition error, not just presentation.

Real scaled-up lander constraints: hard absorber mass budget (~2–5 % of landed mass → ~100–250 g for the 5 kg regime), stowed/deployed envelope volume, footprint/ground-pressure (= base reaction ÷ footprint, a cap and a floor for stability/regolith), and crush stroke (physics floor s ≥ v²/2a_max ≈ 3.3 mm, so H=60–110 mm is mostly a packaging variable, not forced by the 1500 g cap).

Two routes (recommend the hybrid):

  • A — re-parameterize so budgets hold by construction: fix total cell mass m* and solve one axis for it, search in scale-free shape ratios (H/R, H/strut_d, cable_d/strut_d, twist) + one scale variable.
  • B — keep the box, fix the scoring: intensive objectives (SEA_J_per_g and SEA_J_per_cm³, base-reaction peak-g, ground pressure) with mass/volume/footprint + peak-g as Ax outcome constraints under constrained qNEHVI.
  • Hybrid (lander): Route A on the mass budget + dimensionless ratios, Route B for volume/footprint/peak-g.

Edison's verdict (task e43abed6, status success): endorsed the diagnosis and the hybrid, independently reproduced the confound (~6.6× mass / 4.69× vol / 4.0× footprint), and sharpened a few claims I folded back in — reparameterize > outcome-constraints for the mass budget (it's an equality manifold; qNEHVI is for inequalities; Buckingham-π / dimensionless-BO, Senadeera et al. 2025), don't hard-constrain a biased cheap observable (use Tier-C base-reaction only for coarse screening; reserve peak-g acceptance for Tier-B/A/bench), and report fronts at 2–3 fixed mass/envelope budgets rather than one smeared sweep. It also corrected my over-claim that lander F_peak ≈ static load (that's the crutch; lander is a real transient) and noted GEVS/HAVS are requirement proxies, not literal one-number standards.

This is scoped as the analysis + mock review you asked for; the constant-mass-manifold re-parameterization and constrained-qNEHVI wiring are listed as the prioritized follow-on changes.

@sgbaird

sgbaird commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

@copilot by hybrid, do you mean implement two separate campaigns or do you mean incorporate both into the same campaign?

Copilot AI commented Jun 27, 2026

Copy link
Copy Markdown
Contributor Author

@copilot by hybrid, do you mean implement two separate campaigns or do you mean incorporate both into the same campaign?

Same campaign — not two separate ones. The "hybrid" combines Route A and Route B inside one AxClient campaign per regime, not a second campaign. Route A and Route B are just two mechanisms for removing the size confound, and a single campaign can apply both at once:

  • Route A (structural) fixes the binding budget — for the lander that's mass: re-parameterize onto a constant-mass manifold (search scale-free shape ratios H/R, H/strut_d, cable_d/strut_d, twist + drop one axis to hold m*), so the GP never sees a heavier-than-budget design and SEA's denominator is constant.
  • Route B (scoring) handles the remaining budgets in that same campaign — envelope volume and footprint as Ax outcome constraints under constrained qNEHVI, plus intensive objectives (SEA_J_per_g, SEA_J_per_cm³, base-reaction peak g instead of the payload-accel proxy).

So the structure stays one-campaign-per-regime, exactly like sim_bo_campaign.py / pareto_render_campaign.py run today; the hybrid only changes that campaign's coordinates, objectives, and constraints. Crutch and lander stay separate campaigns from each other because they're different regimes (and the crutch can get by with Route B alone), not because of the hybrid. Clarified this in simulations/fair_evaluation_analysis.md (commit be9 — see the new paragraph under "Recommended hybrid").

@copilot by hybrid, do you mean implement two separate campaigns or do you mean incorporate both into the same campaign?

Correction: the commit is cbcf27b (not be9).

@sgbaird

sgbaird commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

@copilot update the BO script(s) based on completing the hybrid approach. Refer to honegumi docs as needed (via context7 if you prefer)

@sgbaird

sgbaird commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

@claude I need you to match the experimental campaign in #102 as best you can as described there, except using simulation methods described here in this extensive thread for the objectives. Run repeat campaigns with different initial seeds (you might need to make a parallelized GitHub actions workflow file for me to add and run). Also compare simulation methods against the actual Sobol batch that was experimentally tested to see which of the many different simulation outcomes in this thread might correlate with the two objectives of interest mentioned in that thread. See if you can account for the sub-100% infill of the PLA, as well.. when you're doing the experiments.

@claude

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude encountered an error after 9m 43s —— View job


Matching the PR #102 experimental campaign with simulation objectives

@sgbaird

sgbaird commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

@claude try again #33 (comment)

@claude

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude finished @sgbaird's task in 42m 41s —— View job


The PR #102 campaign, matched in simulation

Done, committed in df06e08 + 955b62c. Write-up: simulations/pr102_sim_campaign.md.

What "matching PR #102" meant here. bo/t3_prism_bo_campaign.py minimizes two numbers: t180 (CFC-180 TOP/CH5 transmissibility) and e_reb_mJ = e_rebound · m_printed · g · 1.524 m. Nothing in this thread produced either, so I built a drop-tower analogue rather than pretending F_peak/SEA/eta were the same thing. One find worth flagging back: e_rebound in the campaign summary is a restitution velocity ratio, not an energy fractiont_second = 2·e_rebound·v_in/g reproduces every specimen's second-impact time to three digits. PR #102's e_reb_mJ is computed consistently, so nothing is wrong, but the name reads as an energy.

1. Sub-100 % PLA infill

print_infill.py. PR #86 §7 already fits measured ≈ 0.565·m_PLA,solid + 0.986·m_TPU,solid; refitting from the committed CSVs gives 0.556 / 0.995, so the sim uses effective PLA density 700.6 kg/m³ instead of 1240 for every strut, plus a Gibson-Ashby effective modulus (1980 MPa stretch-dominated to 1117 MPa bending-dominated, 1486 MPa at the n=1.5 default) for the tiers that let struts deform.

Two things had to come with it before the masses were right:

  • the idealized volume model this directory uses is not the printed CAD (no joints/housings/scaffold, tendons over-counted), so one factor per material — 1.68 PLA, 0.68 TPU, ~9 %/6 % scatter over the nine designs — carries CAD geometry into the sim. Predicted as-printed mass then lands within 0.7 g mean abs error of the scale readings (18.8–22.6 g predicted vs 18.5–22.3 g measured);
  • the campaign searches base Sobol coordinates but prints the constant-mass rescale of them (scale 0.74–1.08), so evaluate_pr102 projects first. My cube-root solve reproduces the batch table's own scale column to ~2 %.

2. The drop-tower analogue

drop_tower_sim.py: carriage on a slide joint (the rails) carrying CH5, an explicit one-sided Hunt-Crossley PU mat, article bottom vertices ball-anchored to the plate, 9 TPU tendons, 5 g accelerometer mass on the measured top vertex. Channel roles from PR #67 (CH5 = base plate input, tri-axis = top vertex output).

The mat is calibrated to the measured input pulse only: 208.4 G vs measured 208.2 G, 4.08 ms vs the 4.08 ms implied by the measured peak and Δv. Deliberately not to the measured restitution — a mat lossy enough to return 2 % of impact velocity in this model peaks near 300 G, well above the tower, because the rig loses energy through paths the model doesn't carry (rails, anvil, mount). So simulated e_rebound ≈ 0.6 vs measured 0.02–0.05 and is a rank proxy only. Same honesty on t180: sim reads 0.707 for S0 vs measured 1.011, because rigid struts have no bending modes and therefore no mechanism for the amplification 7 of 8 articles show. It can only attenuate.

3. Which simulation outcomes correlate with the two measured objectives

pr102_correlation.py scores the 7 articles that have both a design mapping and a mass (amdjwm maps to no print, so PR #102 skips it and so do I) with ~30 candidate observables from this whole thread.

Measured t180 (n = 7, so |ρ| ≥ 0.79 for p = 0.05; rel_span = the observable's range over its mean):

simulated observable Spearman ρ p rel_span
lander_eta −0.96 0.0005 0.0013
lander_SEA_J_per_cm3 −0.93 0.003 2.38
crutch_SEA_J_per_cm3 −0.89 0.007 1.86
lander_SEA_J_per_g −0.89 0.007 2.93
crutch_SEA_J_per_g −0.86 0.014 1.99
H_mm (design coord, for scale) +0.79 0.036 0.47
sim_t180 (the purpose-built analogue) +0.46 0.29 0.33
sim_in_180_g 0.00 1.00 0.001

Measured e_reb_mJ: nothing clears p = 0.05. Best are R_mm (+0.71, p = 0.07), sim_e_rebound (−0.64, p = 0.12), sim_t180 (−0.57, p = 0.18).

Three readings:

  1. The purpose-built analogue is not the best predictor; the incidental Tier-C observables are. sim_t180 manages ρ = +0.46, while the crutch/lander-regime observables built for a different question rank the bench articles at −0.86 to −0.96, with the physically sensible sign (flatter simulated pulse, more stored elastic energy per unit volume → lower measured transmissibility). The one I'd attach to the campaign GP is SEA_J_per_cm3, not lander_eta despite eta's higher ρ: eta moves 0.13 % across the seven articles (0.7326→0.7334) while volumetric SEA moves 240 %. A perfect ranking over a 0.1 % span is ranking numerical structure until a perturbation study says otherwise — and the earlier Edison reviews in this thread already flagged Tier-C eta as a pinned observable. Take it as a lead to test, not a prior to use.
  2. e_reb_mJ has no simulated predictor yet. Expected, given the mat calibration explicitly gave up on restitution. Model it from bench data alone until a tier carries the rig's loss paths.
  3. sim_in_180_g is ρ = 0.00 by construction, and that's the null control working — a calibrated mat should deliver the same input to every article, and it does.

Infill matters most in the mass channel that e_reb_mJ is built from: at solid density every article's mass is off by ~1.7×, so the objective is wrong by that factor before any physics happens. On t180 the ablation (sim_solid_t180) is indistinguishable at this n.

4. Repeat-seed simulation-only campaign

pr102_sim_campaign.py mirrors PR #102's structure: same box, same two minimized objectives, same mass_g tracking metric, same 9-per-plate batch, same SAASBO step by default, initialized with the nine printed articles attached as completed trials. Ran 3 seeds × (3 rounds × 9) = 36 designs each:

seed final hypervolume best t180 best e_reb_mJ
0 17.79 0.4869 170.05
1 17.59 0.4942 170.04
2 17.59 0.4945 170.01

The nine printed articles score 0.584–0.827 in simulation, so the loop improves ~17 % on the best of them and the seeds agree to under 2 %. All three walk to the same corner: R max, H min, twist min, cable_d min, strut_d the only loose axis. It agrees with the bench on thin cables (6lhxfy, the one real attenuator, is the thin-cable corner) and disagrees on twist, where 6lhxfy sits at the box max. Unlike the regime sims, this model does consume the twist axis, so that is a real disagreement — and given the model cannot amplify at all, it is more likely the model's than the bench's.

5. The parallel workflow (needs you to move it)

I can't write to .github/workflows (GitHub App restriction), so it's staged at simulations/workflows-staged/sim-bo-pr102-matrix.yml:

git mv simulations/workflows-staged/sim-bo-pr102-matrix.yml .github/workflows/

workflow_dispatch with inputs for rounds / batch size / model / seed list; one matrix leg per seed running concurrently, then an aggregate job that downloads every leg and rebuilds the cross-seed mean ± 1σ figures. Worth parallelizing because SAASBO is the wall-clock, not the physics: I verified the SAASBO path end-to-end and one round of 3 designs took 570 s against 0.3 s per simulation.

Caveats

  • n = 7, ~30 observables screened. The leader is a hypothesis for the next batch, not an established transfer function.
  • Simulated t180 cannot exceed ~1: rigid struts can't resonate. Tier B (Newton) or Tier A (PolyFEM) is where amplification would come from, and that is the natural next step if you want the analogue itself to become the predictor.
  • Simulated e_rebound is ~20× the measured value, by the design decision in §2.
  • Infill solidity is one effective scalar per material (walls + density + pattern folded together). The exact per-profile number would come from the BambuStudio CLI's sliced per-filament grams, as PR Add drop-test protocol, Edison synthesis, and first-data analysis #86 §7 says.
  • amdjwm is excluded for want of a design mapping, and it is the second-best measured article, so identifying it would help both this study and PR Add T-3_01 Sobol batch print key (ID-to-spec mapping + as-printed .3mf) #102's ingest.
    · branch copilot/explore-simulations-for-tensegrity

github-actions Bot and others added 2 commits August 21, 2026 17:32
…er analogue, sim-vs-measured correlation study, repeat-seed BO campaign

- print_infill.py: sub-100% PLA infill (0.565 solid fraction, refit 0.556 from
  the committed CSVs), effective strut density/modulus (Gibson-Ashby bracket),
  CAD-vs-model geometry factors, and the PR #35 constant-mass projection.
  Predicted as-printed mass lands within 0.7 g of the scale readings.
- drop_tower_sim.py: MuJoCo analogue of the 60 in / PU-mat drop in the bench's
  own objectives (CFC-180 transmissibility t180, rebound energy e_reb_mJ), with
  the mat calibrated to the measured input pulse (208.4 G / 4.08 ms).
- pr102_correlation.py: every simulated observable in this directory vs the
  seven mapped tested articles. Volumetric SEA tracks measured t180 at
  rho = -0.93; the purpose-built t180 analogue only manages +0.46; nothing
  predicts e_reb_mJ yet.
- pr102_sim_campaign.py: closed-loop simulation-only analogue of PR #102's
  SAASBO campaign, one run per seed, with cross-seed mean +/- 1 sd figures.
- workflows-staged/sim-bo-pr102-matrix.yml: parallel seed matrix for Actions
  (staged outside .github/workflows, which this app cannot write to).

Co-authored-by: Sterling G. Baird <45469701+sgbaird@users.noreply.github.com>
…th check

All three seeds walk to the same corner (R max, H min, twist min, cable_d
min) and agree on best t180 to under 2 percent, improving ~17 percent on the
best of the nine printed articles as scored in simulation.

Co-authored-by: Sterling G. Baird <45469701+sgbaird@users.noreply.github.com>
@sgbaird

sgbaird commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

@claude you should have been starting from scratch, changing the seed for Sobol each time. See how many repeats you can do within your single session. After you correct things, I can go back in and get the workflows set up, but first see how many repeats you can get on your own (10 for example). Noting you might be able to parallelize a bit on your end with your CPUs.

@claude

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude finished @sgbaird's task in 34m 47s —— View job


Ten independent repeats, each drawing its own Sobol batch

You were right, and it was worse than a missing seed argument. Every repeat attached the same nine printed articles as round 0, so the seed reached nothing but the surrogate's own randomness. The "seeds agree to under 2 %" line I reported was arithmetic, not evidence.

Committed in 6301f99 (the fix) and dbe3670 (the ten runs). Write-up: pr102_sim_campaign.md §4.

What changed

--init sobol is now the default: round 0 is the campaign's own nine-point Sobol draw, scrambled with that repeat's seed (passed to Ax's Sobol generator explicitly as well as through AxClient(random_seed=...), so it is pinned to the seed rather than to process state). --init printed keeps the PR #102-exact behaviour for when the question is specifically what the measured batch implies.

One thing had to move with it. The hypervolume reference point was derived from the seed's own round 0, which is harmless when every seed shares round 0 and wrong the moment they do not: a repeat that drew a bad initial batch would be handed a generous reference point and score a larger hypervolume for it. It is now computed once from the nine printed articles, so it is the same number for every seed.

--jobs N runs repeats as separate processes with the numeric libraries pinned to one thread each. Ten repeats, four at a time, took 1457 s on this four-core runner. The fit is the wall-clock, not the physics: the 36 simulations behind a seed cost about 11 s in total.

Ten repeats, 36 designs each

seed final hypervolume best t180 best e_reb_mJ
0 17.83 0.4848 170.20
1 17.36 0.4992 170.17
2 17.43 0.4996 169.89
3 17.39 0.5025 169.59
4 17.75 0.4880 170.20
5 17.57 0.4979 169.57
6 17.26 0.5015 170.18
7 17.31 0.5035 169.73
8 17.96 0.4877 169.00
9 17.18 0.5072 169.59

The third panel is there so the old failure mode stays visible: those are ten different round-0 clouds. Under --init printed they collapse onto one set of nine markers.

The repeats now say something. They start far apart and finish close. After round 0 alone the hypervolume spans 7.71 to 11.07 (13.8 % of its mean) and the best t180 in the initial batch spans 0.584 to 0.646. Four batches later it is 17.50 ± 0.26 (1.51 %), best t180 0.485 to 0.507. So the loop is convergent under resampling of its own initial design. The three shared-round-0 seeds finished at 17.59 to 17.79 against the same reference point, inside the spread of the ten independent ones and near its top, which is what a hand-picked initial batch should do.

All ten walk to the same corner: R max 40 mm, H min 60 mm, twist min 40 deg, cable_d min 3.0 mm. Short, wide, thin-cabled. strut_d is the one loose axis and it is loose across the whole box (6.35 to 12.0 mm across the ten best-t180 designs), so the model is indifferent to it rather than under-resolved on it. The disagreement with the bench is still twist, where 6lhxfy (the one article that genuinely attenuated) sits at the box maximum, and given this model cannot amplify at all, that is more likely the model's error than the bench's.

For the workflow you wanted to set up

simulations/workflows-staged/sim-bo-pr102-matrix.yml now takes an init input and defaults its seed list to [0..9]; each leg is a fully independent campaign. Still needs you to move it, since this app cannot write under .github/workflows:

git mv simulations/workflows-staged/sim-bo-pr102-matrix.yml .github/workflows/

What I did not do

  • These ten used --model botorch (qNEHVI), not the SAASBO step that matches PR Add T-3_01 Sobol batch print key (ID-to-spec mapping + as-printed .3mf) #102. One SAASBO round of 3 designs took 570 s, so ten SAASBO repeats do not fit a session; that is the case for running the matrix in Actions rather than here.
  • I rescoped mid-session from 5 batches to 4 per repeat (36 designs, matching the earlier run's per-seed budget) to fit ten repeats. A first attempt at 5 also left orphaned worker processes competing for the same four cores, which is why the early rounds in the log look slow.
  • The earlier shared-round-0 outputs are kept alongside as outputs/pr102_sim_bo_*_printed_* rather than deleted.
    · branch copilot/explore-simulations-for-tensegrity

github-actions Bot and others added 2 commits August 21, 2026 20:39
…ol seed

The repeats shared round 0: every seed attached the nine physically printed
articles as completed trials, so the seed reached nothing but the
surrogate's own randomness and the seeds agreed to under 2 percent.

--init sobol (now the default) draws each repeat's own nine-point round 0
from that repeat's seed; --init printed keeps the PR #102-exact behaviour.
The hypervolume reference point moves off the seed's own round 0 onto a
fixed one derived from the printed articles, so a repeat that draws a bad
initial batch is not handed a generous reference point for it.

--jobs runs repeats concurrently, one process per seed, with the numeric
libraries pinned to one thread each.

Co-authored-by: Sterling G. Baird <45469701+sgbaird@users.noreply.github.com>
Four batches of 9 per repeat, the same per-seed budget as the earlier
three-seed run, ten repeats in 1457 s on four cores.

The independent draws start far apart and finish close: hypervolume after
round 0 spans 13.8 percent of its mean, and 17.50 +/- 0.26 (1.51 percent)
after four batches.  All ten corner R, H, twist and cable_d identically and
leave strut_d loose across the whole box.

Co-authored-by: Sterling G. Baird <45469701+sgbaird@users.noreply.github.com>
@sgbaird

sgbaird commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

@claude I also need a comparison to random search, a "true optimum" (based on running a whole bunch of the simulations and taking the best one, or some other way that you determine with a much less restricted budget), and whatever other baseline you might want to add (LHS? Something heuristic?). Make sure that you're always saving the results (can commit raw results here), in case we need to look back and change plots or do other analysis. Also, why is there no plot of "running best" for e reb?

@claude

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown

Claude finished @sgbaird's task in 51m 51s —— View job


Baselines, a reference optimum, and the missing e_reb plot

Committed in 72f1989. New script: simulations/pr102_baselines.py. Write-up: pr102_sim_campaign.md §5.

Why there was no running-best plot for e_reb

No good reason. best_e_reb_mJ was computed and written to every CSV from the start and then simply never plotted: plot_seed drew hypervolume and an objective-space scatter, and aggregate drew hypervolume, best_t180, and the round-0 panel. Both now have a running-best panel per objective, and every existing figure has been regenerated from the committed CSVs (no re-simulation needed, which is the point of saving them).

Having it is worth something: the two objectives converge on completely different schedules. e_reb_mJ is essentially done by design 5, inside the initial Sobol batch and before the model exists (200.1 to 174.4 mJ, then only 4.6 mJ more over the remaining 31 designs). t180 barely moves during round 0 and then drops 0.62 to 0.53 on the first model-driven batch. All of the surrogate's work is on t180.

The reference optimum

65,536 scrambled Sobol designs, about 1,800x the campaign's budget, 1,120 s over four processes at 17 ms each, plus a Nelder-Mead polish of the best point under each of 21 weightings (3,408 more evaluations). The non-dominated set of all 68,944 is the ceiling: 247 points, hypervolume 18.024 against the same fixed reference point the campaign uses.

It is a dense sample, not a proof of global optimality. What makes it usable is that the polish moves it essentially nowhere, because the front sits on box bounds and a local optimizer started from the sweep's best points just walks back into the same corners.

The front's geometry is the most actionable thing here. cable_d_mm is pinned at its low bound (3.0 mm, max 3.04 mm) along the entire 247-point front, and twist_deg sits at 40 to 50 deg against a 40 to 80 deg range. Two of the five axes are doing nothing but leaning on a wall. The trade-off is carried entirely by strut_d_mm and H_mm: min-t180 is short/wide/thin-strut (R 40, H 60, strut_d 6.4), min-e_reb_mJ is tall/narrow/fat-strut (R 25, H 110, strut_d 12). If a next plate is being planned, extending the box below cable_d_mm 3.0 and below twist_deg 40 deg is likely worth more than re-searching it as it stands.

Baselines, same 36-design budget, same ten seeds

baseline what it is
random uniform i.i.d. draws; the floor
sobol scrambled Sobol over the whole budget, i.e. the campaign's round 0 extended to fill it, so the gap to the BO is exactly what the surrogate contributes
lhs scrambled Latin hypercube
heuristic compass (pattern) search with a halving step on a normalized weighted sum, budget split over three weightings (0.15 / 0.5 / 0.85) so it yields a spread of trade-offs rather than one point. The seed sets the start and the axis order. This is "turn one knob at a time", formalized

method final HV (mean ± sd) fraction of reference best t180 best e_reb_mJ p vs BO
BO (qNEHVI) 17.50 ± 0.25 97.1 % 0.4972 169.81
compass search 14.49 ± 1.78 80.4 % 0.5408 172.59 9.1e-5
Sobol 11.82 ± 1.11 65.6 % 0.5790 172.17 9.1e-5
Latin hypercube 11.66 ± 1.54 64.7 % 0.5864 172.00 9.1e-5
random search 10.86 ± 1.09 60.3 % 0.5972 172.30 9.1e-5

p is a one-sided Mann-Whitney U on the ten final hypervolumes. 9.1e-5 is the smallest value that test can return at n = 10 against n = 10, so every baseline is completely separated from the BO, no overlap between the two sets of ten.

Three readings:

  1. The surrogate is doing the work, not the space-filling design. The BO's first nine designs are a Sobol batch (Ax's own generator, a different scramble from the sobol baseline's, hence the small offset at design 9: 9.25 against 9.81, with the baseline slightly ahead). The moment the model takes over the traces separate and never re-cross: one model-driven batch takes the BO from 51 % of the ceiling to 83 %, 96 % by design 18, 97 % by design 27. Sobol run out to the full 36 finishes at 66 %.
  2. Sobol and LHS are indistinguishable from each other and barely beat random (65.6 / 64.7 / 60.3 %). At 36 points in 5 dimensions, quasi-random stratification buys very little.
  3. Compass search is the strongest baseline and still loses by a wide margin, and it has the largest seed-to-seed spread of any method (sd 1.78 on hypervolume, 4.04 mJ on best e_reb_mJ). That is the expected signature of a local method on a front whose extremes are box corners: whether a run lands near one depends on where it started.

The BO's spread is also the smallest of the five, sd 0.25 = 1.4 % of its mean against 9 to 12 % for the baselines. Better and more repeatable across ten independent repeats, which is the property that matters when a real evaluation is a print plus a drop session.

Pooled over ten seeds, the BO's points lie along the front and every baseline's are a cloud in the interior. Note the BO does not reach the extreme low-e_reb_mJ tail (R 25 / H 110 / strut_d 12): qNEHVI spends its budget on the knee, where the hypervolume is, and the tail is worth about 0.8 mJ.

Everything is saved

Every evaluation from every run is on disk, so plots and further analysis never need a re-run:

  • outputs/pr102_reference_cloud.csv.gz — all 68,944 reference evaluations (2.4 MB gzipped, pd.read_csv reads it directly)
  • outputs/pr102_reference_front.csv — the 247 non-dominated designs; outputs/pr102_reference_summary.csv
  • outputs/pr102_baseline_<strategy>_seed<k>.csv — 40 runs, each row carrying parameters, both objectives, printed mass, the constant-mass print scale, feasibility flag, hypervolume and both running bests
  • outputs/pr102_baselines_summary.csv — the table above
  • refreshed outputs_bundle.zip (32 MB)

Reproduce: python simulations/pr102_baselines.py --reference --jobs 4 (~21 min) then python simulations/pr102_baselines.py --strategies random sobol lhs heuristic --seeds 0 1 2 3 4 5 6 7 8 9 --jobs 4 (27 s).

Caveat

This compares optimizers on a simulated objective, so it measures search efficiency on this response surface, not accuracy against the bench. Section 3's caveats about the objective itself all still stand (simulated t180 cannot exceed ~1 because rigid struts cannot resonate; simulated e_rebound is a rank proxy at ~20x the measured value). What does transfer is the shape of the problem: 5 continuous axes, 2 objectives, smooth deterministic response, front on the box boundary. On that shape, 36 model-driven evaluations reach 97 % of a 68,944-evaluation ceiling and 36 space-filling ones reach 66 %.

Also: these ten BO repeats are the qNEHVI ones, not the SAASBO step that matches PR #102 exactly. A single SAASBO round of 3 designs took 570 s, so a like-for-like SAASBO baseline comparison needs the staged Actions matrix rather than one session.
· branch copilot/explore-simulations-for-tensegrity

…nce front

The PR #102 simulation-only campaign reported a hypervolume trace with
nothing to compare it against.  Adds pr102_baselines.py: four baselines at
the campaign's own 36-design budget over the same ten seeds, plus a
reference optimum from a 65,536-design Sobol sweep and a Nelder-Mead polish
of 21 weightings.

BO reaches 97.1 % of the reference hypervolume, compass search 80.4 %,
Sobol 65.6 %, LHS 64.7 %, random 60.3 %; every baseline is completely
separated from the BO over ten seeds (Mann-Whitney p = 9.1e-5, the floor at
n = 10).  The front sits on box bounds, with cable_d and twist pinned low
along its whole length.

Also fixes the missing running-best e_reb_mJ panel: the column was computed
and saved but never plotted, in either the per-seed or the aggregate figure.
Every evaluation from every run is written to CSV, including the full
reference cloud, so plots can be redone without re-running anything.

Co-authored-by: Sterling G. Baird <45469701+sgbaird@users.noreply.github.com>
@sgbaird

sgbaird commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

@claude did you apply the right normalization in the objective for mass? I forgot

@claude

claude Bot commented Aug 22, 2026

Copy link
Copy Markdown

No. The mass normalization is wrong, and it is worse than a scale factor

Short version: in the simulated campaign e_reb_mJ was printed mass in disguise. Over the 68,944-design reference cloud, Spearman ρ(e_reb_mJ, mass_g) = 0.99993. Backing the mass out, simulated e_rebound spans 0.61233 to 0.61444, a 0.34 % range, while mass spans 18.42 to 24.96 g, a 32 % range. e_reb_mJ = e_rebound · m · g · h was carrying none of the restitution and all of the mass. "Minimize e_reb_mJ" reduced to "minimize printed mass".

That also explains the thing I reported as a curiosity last night without chasing it: e_reb_mJ was converged by design 5, inside the initial Sobol batch, before the surrogate existed. Finding the lightest corner of a box is not an optimization problem.

The cause. evaluate_pr102 held constant solid CAD mass (30.95 g, PR #35 Route A, round 1). PR #102 stopped doing that in 2f1ca2e, 40 minutes after my first commit, and my later runs did not pick it up. It now holds constant printed mass (20.23 g) with mass_printed_g as a sixth BO parameter in a narrow slab (± 0.457 g, the spec-08 triplicate scatter), so shapes compete at equal mass and the print scatter is attributed to the mass parameter rather than to shape. t180 is fine and needs no mass correction: it is a peak ratio, ρ(t180, mass_g) = −0.008 in the sim, and PR #102 says the same of the measured one.

Fixed and pushed in 801afe3.

The port

pr102_mass_model.py recalibrates PR #102's model from the CSVs already committed here, rather than copying its constants:

fit residual sd, 12 weighed articles
wall + infill, strut-diameter dependent 0.378 g
two flat densities (what I had) 0.927 g
print-to-print scatter, spec-08 triplicate 0.457 g

So the ported model is as accurate as the process is repeatable and mine was twice as coarse. Independent check: re-projected onto 20.23 g, S0 comes out at scale 1.1335 against the 1.1538 it was printed at. The mat recalibrates on the new manifold to an exact match on the input pulse (208.2 G, 4.08 ms).

simulate() can now pin the article's total mass so the simulated inertia agrees with the scale, and the correlation study scores each article at its own weighed mass instead of a batch target.

What changed, on a 256-point Sobol set

constant solid mass (old) constant printed mass (new)
e_reb_mJ relative span 0.316 0.047
mass_g relative span 0.316 0.045
ρ(e_reb_mJ, mass_g) 0.9999 0.997
ρ(e_reb_mJ, e_rebound) 0.505 0.026

The leak is bounded to the declared print scatter now. But it makes a second problem unmissable, and I would rather say it than leave it in a CSV: with mass controlled, this simulation has only one live objective. ρ(e_reb_mJ, e_rebound) = 0.026 means simulated restitution does not respond to the design at all. That follows from the mat calibration decision I documented in §2 last time (calibrated to the measured input pulse, not to the measured restitution, so simulated e_rebound ≈ 0.61 against a measured 0.02 to 0.05). The bench's e_rebound spans 2.5× across the articles, so the measured objective is real; the simulated stand-in is not. Read anything the sim says about e_reb_mJ as mass bookkeeping.

Ten repeats, re-run on the corrected manifold

All ten now land on the identical box vertex: R 40 / H 60 / twist 40 / strut_d 6.0 / cable_d 3.0 / mass at the slab's low edge, t180 = 0.5686 every time. Final hypervolume 10.058 ± 0.0002, a 0.002 % spread against 1.51 % before. Round 0 still starts them 5.59 to 6.81 apart, so the loop is converging, not degenerate at the start.

That collapse is the honest consequence of the fix, not a better result. With mass held constant the problem is effectively single-objective in t180 plus "sit at the light edge of the slab", and the optimum is a corner. strut_d was the one loose axis before and is now pinned, because with mass fixed the strut diameter sets the scale.

The correlation study also moved, and one prior lead did not survive

Re-scored at each article's weighed mass. lander_SEA_J_per_cm3 holds at ρ = −0.93 (p = 0.003, span 231 %) and remains the observable I would attach to the campaign GP. But lander_eta, which led that table at −0.96 last time, fell to −0.71 and switched which objective it leads. I flagged it then as "a ranking of numerical structure until a perturbation study says otherwise"; re-projecting each article onto its own mass was that perturbation, and it failed. A new instance of the same failure appeared: sim_in_180_g, the null control, now reads ρ = −0.89 at p = 0.007 on a 0.09 % span. Any leader whose rel_span is a fraction of a percent is noise with a good p-value.

Reference sweep running now.

View job run · branch copilot/explore-simulations-for-tensegrity

@sgbaird

sgbaird commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

@claude For future session, why would you make mass a variable rather than simply applying some normalization to the objective itself like dividing the rebound energy by the mass? Mass, which is predetermined by the other variables, is more difficult to represent within the optimization framework, because you need to use fixed features which uses some of the API tooling from featurization. See honegumi for this and you'll also need to look at the ax GitHub documentation extensively

Note that there is an earlier session running concurrently

@claude

claude Bot commented Aug 22, 2026

Copy link
Copy Markdown

Claude finished @sgbaird's task in 3m 55s —— View job


Mass as a parameter vs. normalizing the objective

You are right about the simulated campaign, and the numbers say something sharper than I did three hours ago: normalizing would have been the correct move there, and it also shows that the objective definition was never the bug. Nothing committed this session, since the earlier session is mid-edit on these same files.

The distinction that decides it: is mass free or determined?

That is the whole question, and the two campaigns answer it differently.

In PR #102 mass is free. Its five base coordinates fix the article's shape only, because the constant-mass projection uniformly rescales every dimension including the joint. The overall scale is a genuine sixth degree of freedom, and mass_printed_g is that scale re-expressed in grams. (shape, mass) maps to exactly one article, no degeneracy, no redundancy. It also happens to be measured per print with 0.457 g of scatter, so carrying it lets the GP attribute part of the round-1 spread to mass instead of to shape. That is a real parameter, and the docstring at t3_prism_bo_campaign.py argues it correctly.

In my sim it is determined. evaluate_pr102 takes R_mm, H_mm, twist_deg, strut_d_mm, cable_d_mm as absolute millimetres, so mass = f(shape) exactly, with no scatter (deterministic sim, no printer). Bolting mass_printed_g on as a sixth axis there would create precisely the degenerate space you are describing. So porting PR #102's six-parameter setup, which is what I said I was about to do, would have been cargo-culting the machinery without the condition that justifies it.

Why it is not just expensive in Ax, it is inexpressible

Worth spelling out, because it is stronger than "more difficult":

Also worth noting from PR #102's own experience with the slab: at the full 0.457 g print scatter, qNEHVI put all nine suggestions on the light edge, so shapes were chosen at 19.77 g and reported at 20.23 g. That is the mass axis being exploited as a gradient rather than modelled, which is another argument for removing it from the search space where you can.

What normalizing actually reveals, on both sides

Measured batch, the 7 articles with a mass (simulations/data/pr102/t3-prism-bo-batch-drop-results.csv):

ratio max/min rho vs e_reb_mJ
e_rebound (dimensionless) 2.46x 1.000
mass_g 1.19x 0.071 (p = 0.88)

On the bench, e_reb_mJ and e_rebound are rank-identical. The mass factor carries essentially no ordering information, because restitution moves 2.5x against mass's 1.2x. So dividing by mass would change nothing on the bench, and PR #102's choice not to is right for exactly the physical reason it gives: delivered millijoules is what the payload receives, and keeping the grams in re-penalizes a design that adds them.

Simulated reference cloud, all 68,944 evaluations in pr102_reference_cloud.csv.gz:

rel. span rho vs mass_g
e_reb_mJ 0.354 0.99993
e_rebound = e_reb_mJ / (m g h) 0.0034 0.497
mass_g 0.316 1

So the correction to my last comment: the mass normalization was never the real fault. Dividing by mass, which costs one line, removes the confound completely and exposes what is underneath, which is that my simulated restitution varies by 0.34 % across the entire box. That is the mat calibration decision from section 2 of the write-up coming home: the mat was fit to the input pulse and explicitly not to the measured restitution, so the model has no design-dependent loss mechanism. Making mass a parameter would have frozen that confound at one mass rather than fixing it, and imported the fixed-features machinery for nothing.

One more thing normalization surfaces that the raw objective hides: the normalized rebound is 0.79 rank-correlated with t180 and flips the sign of the geometry dependence on R_mm (-0.62 normalized against -0.03 raw) and H_mm (+0.57 against +0.02). So at Tier C the second objective, once de-confounded, is a 0.34 %-span near-duplicate of the first. The simulated campaign is effectively single-objective on t180, and the two-objective hypervolume results I reported (97 % of the reference ceiling, and so on) were measuring search efficiency on a surface whose second axis is mostly printed grams.

t180 needs no mass treatment on either side: rho vs mass is -0.009 in the sim and +0.43 (p = 0.34, n = 7) on the bench, consistent with PR #102 leaving it a ratio.

What I would do instead, with no fixed features anywhere

  1. Re-parameterize, do not constrain. Search the four scale-free shape ratios (H/R, H/strut_d, cable_d/strut_d, twist) and solve the single overall scale in closed form so printed mass equals m* exactly. That is bo_evaluator.design_from_shape_ratios, already written for the Route A recommendation in fair_evaluation_analysis.md; it needs re-pointing from solid CAD mass at printed grams. Every parameter stays a plain RangeParameter, mass is constant by construction so e_reb_mJ and e_rebound differ by a constant, and this is PR Add T-3_01 Sobol batch print key (ID-to-spec mapping + as-printed .3mf) #102's setup written in the sim's own coordinates rather than a copy of its Ax plumbing.
  2. If mass should stay free, normalize and constrain the outcome. Keep the five absolute-mm axes, minimize e_rebound, and put mass in as an Ax outcome constraint or a third objective. Outcome constraints are inequalities on metrics, which Ax handles natively, and it keeps a design from getting heavy for free once the millijoule term is gone.
  3. Do not put mass in the search space over absolute-mm coordinates. Which is what I was about to do.

Route 1 is what I would pick for the sim, since it also makes the sim and the bench search the same manifold, which is a precondition for the correlation study in section 3 meaning anything.

Handoff

Not committing, to stay clear of the concurrent session. If it has already landed the six-parameter port, the cheap unwind is to drop the mass parameter, switch the objective to e_rebound, and re-point project_constant_mass at printed grams; the reference cloud on disk is enough to redo every figure without re-simulating, since e_reb_mJ, mass_g and the parameters are all in it.

Separately: fixing the simulated restitution matters more than any of this. As it stands the sim's second objective is 0.34 % wide and mostly redundant with the first, so t180 is carrying the campaign alone.
· branch copilot/explore-simulations-for-tensegrity

…inted mass

e_reb_mJ = e_rebound * m * g * h is an absolute energy, so it is
proportional to the article's printed mass. evaluate_pr102 was projecting
onto PR #35's constant-*solid*-mass manifold (30.95 g), which leaves
printed mass free: over the committed 68,944-design reference sweep,
printed mass spans 32 %, simulated e_rebound spans 0.34 %, and
rho(e_reb_mJ, mass_g) = 0.99993. The objective was the mass.

PR #102 fixed the same hole on the bench side in 2f1ca2e by projecting
onto constant *printed* mass and carrying mass_printed_g as a sixth BO
parameter in a narrow slab (target +/- 0.457 g, the spec-08 triplicate
scatter). This ports that projection (pr102_mass_model.py, recalibrated
from the CSVs already committed here: residual sd 0.378 g over 12 weighed
articles against 0.927 g for the flat two-density fit) and wires it in.

Also: simulate() can now pin the article's total mass, so the simulated
inertia agrees with the scale; the correlation study scores each article
at its own weighed mass; the mat is recalibrated on the new manifold
(S0 input peak 208.2 G, pulse 4.08 ms, both exact).

Co-authored-by: Sterling G. Baird <45469701+sgbaird@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Begin exploring state-of-the-art simulations for tensegrity, tensegrity-like structures, and other related methods

4 participants