Non-planar 3D fracture solver
Non-planar tip kinking + NF branching ship with unit-level drift-guards only — no published error band against measured geometry.
Fully-3D non-planar fracture geometry via `src/lib/nonPlanar3D/{surfaceMesh,ddm3D,tipKinking,nfBranching,pipeline,mtsPropagation,stressFieldSampler}.ts` — quad surface mesh with per-face propagation history, 3-D DDM influence operator (Okada-style half-space), Erdogan-Sih maximum-hoop-stress tip-kinking criterion with operator-tunable kink-angle clamp, and natural-fracture branching gated by Renshaw-Pollard / Gu-Weng crossing criteria. M1 (surface mesh + DDM) + M2 (Erdogan-Sih tip kinking) + M3 (NF branching) + M4 per-vertex E′/ν heterogeneity (`MeshVertex.ePrimePsi` / `poissonRatio` → opt-in via `perVertex: true` on `runNonPlanar3DPipeline`; per-face E′ = mean of 3 vertex E′_v with E′_v = E_v/(1−ν_v²) when ν_v defined, scalar `ePrimePsi` fallback per vertex; layered config wins when both supplied; omitted ≡ false ≡ byte-identical legacy run) + M4 out-of-plane tilt for sub-vertical fractures (per-edge / per-step tilt field plumbed through `advanceTipRow` — length-preserving `cos τ` in-plane × `sin τ` +y; collapses byte-for-byte when omitted) + shared-vertex weld for T-junction reconvergence (`tipReconvergenceWeld: { enabled, tolFt? }` re-uses `weldNearbyVertices` so any new tip vertex landing within `tolFt` of a parent vertex folds onto it; per-step `tipWeldedVertexCount` + `tipWeldedRemovedFaceCount` surfaced on every `TimeStepRecord`) + M2 stress-driven curvature loop (`stressDrivenCurvature: { enabled, evaluator, maxCurvatureRadPerFt? }` — live Δσ tensor evaluator feeds per-edge σ_Hmax azimuth via `principalDirectionsFromTensor2D`, capped by `curvatureLimitedKinkDeg`; omitted ≡ disabled ≡ isotropic σ collapses byte-identically to legacy baseline) + multi-stage orchestrator `runMultiStageNonPlanar3DPipeline` (`src/lib/nonPlanar3D/multiStagePipeline.ts`) drives N stages in lockstep and snapshots cross-stage frac–frac welds via `mergeIntersectingStages` under a `crossStageMerge: { tolFt, cadenceSteps?, minStageGap?, debug? }` knob — UI surfaces (`NonPlanar3DCrossStageMergeCard` on `/non-planar-3d`, `downhole.nonPlanar3D.crossStageMerge.v1` store) and a public SDK endpoint `POST /api/public/sdk/v1/non-planar-3d/multi-stage` accept the same knobs and return `crossStageMergeHistory` (per-step welded-pair stats + optional combined-mesh debug snapshots); omitted ≡ N independent single-stage runs (byte-identical histories) + pipeline driver + three.js viewer at `/non-planar-3d` (sliders maxKinkDeg / advanceFt / steps / SHmax + criterion select; viridis face-of-birth tint) + per-simulation Results tab `NonPlanar3DResultsCard`. Validation toggle on `/planar3d-validation` (`Switch to non-planar 3D viewer →`) gives engineers a one-click jump between the planar Sneddon comparator and the non-planar viewer. **In-Newton coupling LIVE @ Phase 8 inc 6** via `nonPlanarCoupling` on `coupledNewtonStep` (`src/lib/planar3d/newtonNonPlanarCoupling.ts`) — a persistent `SurfaceMesh` survives every Newton iterate and is advanced ONE pipeline step per accepted iter using a kernel-derived net pressure (mean `pMesh`, Pa→psi), so M1+M2+M3+M4 curvature history + T-junction welds accumulate across iterates instead of being rediscovered each call; `stepsPerIter` (default 1), `maxStepsTotal` (default = Newton `maxIter`), and `netPressurePsiFromKernel` are operator-tunable; caller-supplied `pipelineConfig.dfn` is passed straight through so the §12 DFN dispatcher runs inside the Newton outer loop transitively; result surfaces `nonPlanarMesh` / `nonPlanarHistory` / `nonPlanarStepCount`. Off (undefined) by default — kernel byte-identical to today. Drift-guards: `surfaceMesh.test.ts` (4) + `ddm3D.test.ts` (4) + `tipKinking.test.ts` (17 incl. 2 tilt unit tests) + `nfBranching.test.ts` (9) + `pipeline.test.ts` (15 — 4 baseline + 3 non-planar retention + 4 out-of-plane tilt + 4 T-junction reconvergence weld) + `mtsPropagation.test.ts` (9) + `stressFieldSampler.test.ts` (4) + `pipeline.curvature.test.ts` (4 — parity collapse · anisotropy drives kink · zero-curvature flat · curvature cap honored) + `multiStagePipeline.test.ts` (8 — collapse-to-N · cadence skip · tight pair welds · separated pair no weld · minStageGap default · debug arrays gating · empty step) + `nonPlanar3DCrossStageMergeStore.test.ts` (6) + `ddm3DPerVertex.test.ts` (6) + `pipeline.perVertex.test.ts` (4) + `pipelineProppantBridging.test.ts` (5 — B3 Hertz-Mindlin tip bridging opt-in) = 95 tests (plus `coupledStepNonPlanar.test.ts` — in-Newton coupling contract). Phase-B3 — Hertz-Mindlin proppant-DEM tip bridging wired into `runNonPlanar3DPipeline` via opt-in `proppantBridging: { enabled, grainDiameterIn?, transferEfficiency?, criticalRatio? }`: each step evaluates N_b = w/d at the leading edge and transfers σ_rock = η · N_b · p_net into local σ_h via wrapped `stressAt`; surfaces `tipBridgingActive` / `tipNbRatio` / `tipSigmaTransferPsi` on every `TimeStepRecord` and a 'Tip bridging' column in `NonPlanar3DResultsCard` step scoreboard; omitted ≡ {enabled:false} ≡ legacy byte-identical.
In-Newton coupling into `coupledNewtonStep` shipped @ Phase 8 inc 6 (see today). Remaining: bridge per-face σ_Hmax telemetry into the live-pumping observability surface. Field-validation gating shares the `/projects/$p/workspaces/$w/field-validation` ingest path (microseismic catalogs + offset DFITs). **Moat M5 (full 3D auto-history-match) primitive + end-to-end adapter LIVE** — pure `src/lib/nonPlanar3D/mesh3DAutoHistoryMatch.ts` PSO/coord optimiser + `mesh3DAutoHistoryMatchAdapter.ts` end-to-end adapter (`applyMesh3DKnobs` + `buildMesh3DForwardEvaluator` + `tuneMesh3DAgainstObservations`) that scores real `runNonPlanar3DPipeline` history against `Mesh3DObservationTargets` and returns `{result, tunedInputs, tunedHistory}` consumable straight by the Newton wrapper's `nonPlanarCoupling.pipelineConfig`. **M5 UI card LIVE** — `Mesh3DFullAutoHmCard` mounted at the bottom of `/non-planar-3d/auto-hm` wires the adapter end-to-end: target inputs (footprint area / tortuosity / opening) + knob toggles (E′× · p_net× · kink× · adv×) + PSO particles/iters drive `tuneMesh3DAgainstObservations` and render residual/Δ/iters/evals/steps summary chips, per-knob best values, and a target-vs-tuned Δ table. Drift-guards: `mesh3DAutoHistoryMatch.test.ts` (9) + `mesh3DAutoHistoryMatchAdapter.test.ts` (9).
- Phase 8 inc 6shipped
nar viewer. **In-Newton coupling LIVE @ Phase 8 inc 6** via `nonPlanarCoupling` on `coupledNewtonStep` (`src/lib/planar3d/newtonNonPlanarCoupling.ts`) — a persistent `SurfaceMesh` survives every Newton iterate and is advanced ONE pipeline …
- Phase 8 inc 6planned
ling into `coupledNewtonStep` shipped @ Phase 8 inc 6 (see today). Remaining: bridge per-face σ_Hmax telemetry into the live-pumping observability surface. Field-validation gating shares the `/projects/$p/workspaces/$w/field-validation` in…
| Geometry | Quad surface mesh, 3-D DDM half-space influence operator |
| Kinking | Erdogan-Sih maximum hoop stress with operator kink-angle clamp |
| Crossing | Renshaw-Pollard / Gu-Weng natural-fracture criteria |
- No error band against measured fracture geometry — treat predicted paths as scenarios, not forecasts
- Tip-kinking angle is clamp-sensitive; results move with the operator-set limit
- Curvature loop needs a live Δσ evaluator; isotropic stress collapses to a planar path