# Tet + buckling pipeline on highest-resolution OBJ — does it resolve Finding 4? **Date**: 2026-05-05 **Driver commit**: b5b82ee (canonical OBJ switched to `structural-full-office-highest-resolution.obj`, 495 MB). **Question**: Finding 4 (`reports/2026-05-04--findings.md`) attributes the spurious low-eigenvalue buckling modes to sliver tetrahedra at panel joints in the merged tet mesh. The hypothesis: a finer raw-triangle input from the highest-resolution OBJ might reduce or eliminate those slivers and clean up the buckling spectrum. ## Headline **The high-resolution OBJ is strictly worse for the merged-tet pipeline than the previous OBJ — the tet mesh cannot even be built.** Finding 4's concern is not resolved by raising input-OBJ resolution; if anything it is reinforced. The merged-mesh approach itself, not the input triangulation density, is the limiting factor. ## What was attempted Per the geometry-switch sequence: 1. Old-OBJ tet mesh backup: `reports/full_dome_merged.vtu` → `reports/full_dome_merged_old_obj.vtu` (preserved before any regeneration attempt). 2. Re-build the merged tet mesh with the new panels_npz cache (which was regenerated against the highest-res OBJ in commit b5b82ee): `python3 tools/build_assembly_mesh.py`. 3. (Planned, contingent on step 2 succeeding) re-run linear-tet cross- check on gravity baseline; re-run buckling cross-check on snow + uplift baseline; compare BLF spectra and mode-1 smoothness against the old-OBJ baseline. ## What happened Steps 1 and 2 ran. **Step 2 failed** at gmsh's volume-meshing stage. Steps 3 are blocked because `reports/full_dome_merged.vtu` could not be regenerated; the linear-tet and buckling cross-check tools both read from that file path. ### Mesh-build failure detail From `reports/build_assembly_mesh_highres.txt`: ``` Loaded 82 panels, 70 rhombic. Target element size: 80.0 mm building corner network (70 panels, dedup_tol=30.0 mm)... 173 unique corners (avg 1.62 panels per corner). built 70/70 panel skin pieces (346 points, 1426 lines, 1022 unique triangles). classified faces: outer=924 inner_shared=98 meshing (target size 80.0 mm)... Exception: PLC Error: A segment and a facet intersect at point ``` The corner-network and panel-skin construction succeeded; the failure is in tetgen's PLC (Piecewise Linear Complex) volume meshing step. The error means the input PLC is geometrically inconsistent — at least one segment (1D edge of the panel skins) passes through the interior of a triangular facet. This is a topological pathology that no element-size tweaking will fix. ### Why does the highest-res OBJ trigger this when the old OBJ did not? The corner-network construction in `src/zomestruct/fea/assembly_mesh.py::build_corner_network` dedups panel corners with `dedup_tol_mm = 30.0`. Each panel contributes 4 corners; with 70 rhombic panels and full sharing at junctions you'd expect on the order of 80–90 unique corners (cf. the SHELL pipeline, which uses a 300 mm tolerance and gets 89 unique corners — see `reports/2026-05-04--shell-fea-from-scratch.md`). The new OBJ produces **173** unique corners at the 30 mm tolerance — about 1.62 panels per corner instead of 70·4/89 ≈ 3.1 panels per corner. That means the highest-res OBJ's corner positions sit further apart at junctions (likely because the finer triangulation snaps each panel's corner to a slightly different vertex of its mesh, with spreads larger than 30 mm). At those junctions, two panels' "corner" positions are now distinct points joined by short ribbons of inner- shared triangles — and some of those short edges intersect the neighbouring panel's outer face. tetgen sees the inconsistency and refuses to mesh. Notes: - The corner *count* alone is not necessarily evidence of pathology (a few extra unique corners could be benign). The *PLC error* is the hard evidence: the input is non-manifold or self-intersecting, which the previous OBJ's coarser triangulation did not produce. - Increasing `dedup_tol_mm` (e.g. to 100 mm or 300 mm as the shell pipeline does) would likely close the gaps and recover a meshable PLC, but that's a source-code change to `build_assembly_mesh.py` / `assembly_mesh.py`, which is out of scope for this read-only investigation. Recording the option for later work below. ## Comparison to old-OBJ baseline (unchanged, since new mesh failed) The old-OBJ tet mesh and its results (preserved in `reports/full_dome_merged_old_obj.vtu` and the original `reports/opensees_*` text outputs) are still the canonical reference for the merged-tet pipeline: | Metric | Old-OBJ (preserved) | High-res OBJ (this run) | |--- |--- |--- | | Tet mesh built? | yes | **no — gmsh PLC error** | | n_nodes | 20 187 | n/a | | n_tets | 57 725 | n/a | | reorient_tets flipped (neg-jac) | 17 / 57 725 (0.03%) | n/a | | n unique corners (dedup_tol=30 mm) | (not previously logged) | 173 | | Buckling case | Old-OBJ ccx BLF (mode 1–4) | Old-OBJ mode-1 smoothness | High-res OBJ | |--- |--- |--- |--- | | snow, baseline | 4.886 / 13.71 / 16.22 / 31.92 | 1.15 (smooth, PASS) | not run | | uplift, baseline | 3.356 / 4.566 / 11.43 / 483.5 | 1.15 (smooth, PASS) | not run | | Gravity baseline cross-check | Old-OBJ | High-res OBJ | |--- |--- |--- | | skfem u_p99 / VM_p99 [mm / MPa] | 11.93 / 1.5433 | not run | | ccx u_p99 / VM_p99 [mm / MPa] | 6.886 / 0.0472 | not run | | OpenSees u_p99 / VM_p99 [mm / MPa] | 6.138 / 0.0472 | not run | | ccx vs OpenSees agreement | exact (single-step) | not run | Linear-tet cross-check on the new mesh, buckling cross-check on snow and uplift, and BLF-spectrum comparison were all blocked by the mesh failure. The old-OBJ numbers above remain the system of record. ## Verdict on Finding 4 **Finding 4 is NOT resolved by raising input-OBJ resolution.** The sliver-tet artefact is a property of the *merged-tet topology* (panels joined by node coincidence within a finite tolerance, then volume- meshed by tetgen), not of the input-OBJ triangulation density. With the highest-res OBJ: - The previously-coarser triangulation that *happened* to produce a meshable PLC was, in retrospect, hiding the same geometric drift inside its facets. The sliver-tet symptom on that mesh is the visible tip of a non-manifold-junction iceberg. - The finer triangulation removes the cushion: the same junction- drift now manifests as edge-pierces-facet, and tetgen rejects the PLC outright. - Either way, the merged-tet model is not a faithful representation of the panel assembly; it is a discretisation artefact. In the original Finding 4 wording: *"the merged-mesh joint approach produces sliver tetrahedra and near-zero-stiffness regions where joints are bonded by node merging within tolerance."* The high-res OBJ promotes this from "produces slivers" to "is geometrically infeasible" — same root cause, more visible failure. ## Recommendation — next move 1. **Don't trust the merged-tet buckling FE** for life-safety conclusions. The hand-calc shell-buckling D/C of 0.05 (from smoothed-sphere theory) and the higher-mode FE values (10–500× design) remain the trustworthy upper bounds; the marginal mode-1 BLFs (3.4 / 4.9 / 4.0 / 22.5) are mesh artefacts and should not drive a structural verdict. 2. **The shell-convergence finding (2026-05-05) and this tet-buckling finding tell a single story**: faceted CAD with kink-line joints is a singular geometry for *both* shell and continuum-tet formulations. Refining the discretisation does not converge either pipeline. The right next step is to physically model joint stiffness — discrete rotational springs along each panel edge, or small fillet patches with reduced stiffness — rather than to keep refining a mesh of an unphysical CAD. 3. **If a tet-mesh result is genuinely needed**, the path forward is not "use a finer OBJ". It is one of: - Increase `dedup_tol_mm` in `tools/build_assembly_mesh.py` to ~100 mm (matching the shell pipeline's looser tolerance) so the corner network heals over and the PLC becomes meshable. This would re-create the previous (sliver-prone) regime, with the same Finding-4 caveats. - Replace the merged-tet pipeline with a properly-modelled joint family: panels as separate volumes, joints as explicit gap- fillet volumes with measured stiffness. This is a meaningful pipeline rewrite, not an OBJ swap. 4. **No source-code changes were made for this investigation.** `tools/build_assembly_mesh.py` and `src/zomestruct/fea/assembly_mesh.py` are unchanged; only the panels_npz cache (already regenerated by commit b5b82ee) and the captured stdout transcript differ. The old-OBJ merged VTU is preserved at `reports/full_dome_merged_old_obj.vtu` so the existing tet/buckling tools continue to work against the canonical baseline. ## Files touched in this commit - `reports/full_dome_merged_old_obj.vtu` — old-OBJ snapshot (preserved for continuity; gitignored by default, force-added). - `reports/build_assembly_mesh_highres.txt` — captured stdout of the failed mesh-rebuild attempt (gitignored, force-added). - `reports/2026-05-05--tet-buckling-on-highres-obj.md` — this document. - `reports/2026-05-04--findings.md` — appended a one-paragraph pointer in Section 6. The linear-tet (`reports/opensees_crosscheck_gravity_baseline_highres.txt`) and buckling (`reports/opensees_buckling_{snow,uplift}_baseline_highres.txt`) re-runs were planned but could not be executed because the new merged VTU does not exist. No `*_highres.txt` files for those steps exist.