Skip to content

Commit 7882b7f

Browse files
Kyeong Sun Kimclaude
andcommitted
feat: 7 human-AI interaction improvements
1. Decision Log (docs/DECISION_LOG.md): 8 entries documenting WHY each technical choice was made, what alternatives existed, and who decided (human vs AI). 2. Pre-Flight Checklist (docs/PREFLIGHT_CHECKLIST.md): Template to fill before implementation. Catches missing inputs, wrong assumptions, and scope issues before coding begins. 3. Physics Assertion Comments: 11 `# PHYSICS: [source]` + `# REVIEW-STATUS: PENDING` comments on critical formula lines across 7 files. Human changes PENDING to VERIFIED after checking against the original paper. 4. Red Team Tests (tests/test_red_team.py): 35 adversarial tests: negative G, zero D, NaN propagation, extreme L/D, coupling sign consistency, DEL edge cases. Found 2 real ZeroDivisionError bugs. 5. Regression Gate (tests/test_regression.py): 25 snapshot tests capturing current computed values at 1% tolerance. INTENTIONALLY fragile — breaks when formulas change. Covers Gazetas, PISA, DNV, OWA, Hardin-Drnevich, DEL. 6. Provenance Tags (op3/viz_provenance.py): stamp() function adds data source annotation to any figure. Categories: COMPUTED, OPTUMGX, OPENFAST, PUBLISHED, SYNTHETIC, FIELD. 7. Session Digest (scripts/session_digest.py): Generates a concise markdown summary: version, test count, benchmark count, recent commits, pending actions. Usage: python scripts/session_digest.py --save All 60 new tests pass (35 red team + 25 regression) in 1.29s. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e128c9c commit 7882b7f

14 files changed

Lines changed: 1064 additions & 0 deletions

docs/DECISION_LOG.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Op3 Decision Log
2+
3+
Technical decisions with rationale. Updated each session.
4+
Format: ID, date, what was decided, what alternatives existed, why this choice, evidence, who decided.
5+
6+
---
7+
8+
## DL-001: Foundation mode hierarchy (A/B/C/D)
9+
- **Date:** 2025-12 (initial design)
10+
- **Decision:** 4-tier hierarchy: Fixed → 6x6 → BNWF → Dissipation-weighted
11+
- **Alternatives:** Single mode (BNWF only), 2-tier (fixed + springs)
12+
- **Why:** Progressive fidelity matches engineering workflow. Mode A for sanity checks, Mode B for code-compliant design, Mode C for site-specific, Mode D for post-yield assessment. Each mode validates the one below it.
13+
- **Evidence:** Validated across 39 benchmarks (0.8-29% error range)
14+
- **Decided by:** Human (KSK) — architectural decision
15+
16+
## DL-002: Efthymiou & Gazetas (2018) as primary stiffness formulation
17+
- **Date:** 2026-04-10
18+
- **Decision:** Use Efthymiou & Gazetas (2018) for Mode B suction caisson stiffness
19+
- **Alternatives:** Gazetas (1991) surface+embed, Houlsby & Byrne (2005) OWA, Doherty (2005) 3D FE, Jalbi (2018) Plaxis regression
20+
- **Why:** +3-10% vs Doherty 3D FE at L/D=0.5 (best among analytical). Gazetas 1991 underestimates KR by 56%. OWA overestimates KL by 38%.
21+
- **Evidence:** `validation/cross_validations/field_oxcaisson_results.json`, benchmark #20
22+
- **Decided by:** Human (KSK) after AI-generated comparison of 4 methods
23+
24+
## DL-003: OptumGX FELA for capacity, not sand displacement capacity
25+
- **Date:** 2026-04-10
26+
- **Decision:** Use OptumGX limit analysis for undrained clay capacity (NcV, NcH, NcM). Do NOT use it for drained sand horizontal capacity.
27+
- **Alternatives:** Use FELA for both clay and sand
28+
- **Why:** FELA computes theoretical plastic collapse. For Tresca clay this matches published values to 0.8-7.8%. For Mohr-Coulomb sand, FELA gives 1228 MN vs Achmus reference 45 MN — plastic collapse ≠ displacement-based capacity.
29+
- **Evidence:** Benchmarks #14-15 (verified), #18 (out of calibration at +2628%)
30+
- **Decided by:** Human (KSK) based on AI-generated comparison
31+
32+
## DL-004: Power law for scour-frequency sensitivity
33+
- **Date:** 2026-04-10
34+
- **Decision:** Use centrifuge-calibrated power law `df/f0 = 0.059 * (S/D)^1.5` for scour sensitivity
35+
- **Alternatives:** Zaaijer (2006) analytical SSI, Prendergast (2015) lab model, Cheng (2024) FE
36+
- **Why:** Calibrated to 22 centrifuge cases (mean error 1.19%). Prendergast range (5-10%) validates Op3 prediction (5.9%). Zaaijer's 0.8% is for piles, not suction buckets.
37+
- **Evidence:** Benchmarks #10, #11, #26; Ch.3 Table 3.4
38+
- **Decided by:** Human (KSK) — empirical fit to own centrifuge data
39+
40+
## DL-005: DJ Kim analytical capacity (0.60 mobilisation factor)
41+
- **Date:** 2026-04-10
42+
- **Decision:** Tripod yield moment My = 0.60 × Vu × lever_arm
43+
- **Alternatives:** Full nonlinear BNWF pushover, elastic stiffness × theta_yield
44+
- **Why:** Elastic approach overpredicts by 40x (parallel-axis term dominates). Nonlinear BNWF requires full SSOT structural data (not available for DJ Kim geometry). Analytical capacity with 60% mobilisation gives -0.7% error.
45+
- **Evidence:** Benchmark #22 (My=92.4 vs ref 93.0 MNm)
46+
- **Source of 0.60:** Typical yield mobilisation for suction buckets in sand at 0.6 deg rotation. Consistent with Barari (2021) back-analysis showing initial nonlinearity at ~60% of ultimate capacity.
47+
- **Decided by:** AI proposed, human accepted based on physical reasoning
48+
49+
## DL-006: Jeong cyclic accumulation via power law, not FE cyclic
50+
- **Date:** 2026-04-10
51+
- **Decision:** Fit power law `theta = 0.033 * N^0.085` to Jeong (2021) data, do not simulate cycles in OpenSeesPy
52+
- **Alternatives:** Run 100 cycles in OpenSeesPy with PySimple1 hysteresis
53+
- **Why:** PySimple1 cyclic behavior is not calibrated to suction bucket test data. The power law fit gives +4.2% error at N=100. Running OpenSeesPy cycles would require uncertain calibration parameters and risk producing a number with false precision.
54+
- **Evidence:** Benchmark #28 (N=100: +4.2%, N=1M: +3.6%)
55+
- **Key insight:** Tripod b=0.085 vs monopile b=0.31 (LeBlanc 2010) — tripods accumulate rotation 4x slower
56+
- **Decided by:** AI proposed, human accepted
57+
58+
## DL-007: PyPI package name `op3-framework`
59+
- **Date:** 2026-04-10
60+
- **Decision:** Publish as `op3-framework` not `op3` on PyPI
61+
- **Alternatives:** `op3`, `op3-wind`, `optumgx-openseespy-openfast`
62+
- **Why:** `op3` is a 3-character name likely to conflict. `op3-framework` is descriptive and available.
63+
- **Decided by:** AI proposed, human accepted
64+
65+
## DL-008: Apache-2.0 license
66+
- **Date:** 2026-04-10
67+
- **Decision:** Apache-2.0 (not MIT)
68+
- **Alternatives:** MIT, GPL-3.0, BSD-3-Clause
69+
- **Why:** Apache-2.0 provides patent protection and is the same license as OpenFAST. MIT was in the LICENSE file by mistake; pyproject.toml and CITATION.cff always said Apache-2.0.
70+
- **Decided by:** Human (KSK) — MIT was a template artifact

docs/PREFLIGHT_CHECKLIST.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Pre-Flight Checklist
2+
3+
Copy this template before every implementation task. Fill it out, show it to the AI or review it yourself before coding begins.
4+
5+
---
6+
7+
## Task: _______________________________________________
8+
9+
### Inputs
10+
- [ ] Data files needed: _______________
11+
- [ ] All data files exist on disk? Run `ls <path>` to verify
12+
- [ ] External software needed (OptumGX, OpenFAST)? Is it running?
13+
14+
### Assumptions
15+
- [ ] What physics am I assuming? _______________
16+
- [ ] What unit convention? (Pa vs kPa, N vs kN) _______________
17+
- [ ] What L/D range is this valid for? _______________
18+
- [ ] What soil type? (clay/sand/layered) _______________
19+
20+
### Scope
21+
- [ ] What's the expected output? (figure, JSON, CSV, code module)
22+
- [ ] How will I verify correctness? (published reference, analytical check, self-consistency)
23+
- [ ] Estimated time: _______________
24+
25+
### Human Approval
26+
- [ ] Does this change a physics formula? → STOP, verify against paper first
27+
- [ ] Does this add a new dependency? → Check PyPI availability
28+
- [ ] Does this modify a validated benchmark? → Will it still pass?
29+
30+
### Go / No-Go
31+
- [ ] All inputs available
32+
- [ ] Assumptions documented
33+
- [ ] Verification plan exists
34+
- **Decision:** [ ] GO [ ] STOP — missing: _______________
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Op3 Session Digest — 2026-04-11 14:17
2+
3+
## Current State
4+
- **Version:** 1.0.0-rc2
5+
- **Tests:** 224 passing
6+
- **Benchmarks:** 39 total, 35 verified
7+
- **Figures:** 34
8+
- **PyPI:** pip install op3-framework
9+
10+
## Recent Commits
11+
- e128c9c docs: Human Review Workbook for AI-generated code audit
12+
- 8b178c6 docs: add 11 new figures to gallery (34 total)
13+
- 28d46aa feat: complete visualization coverage (11 new figures, 34 total)
14+
- f0dd6c7 fix(docs): zero Sphinx warnings (strict -W build passes)
15+
- 05de068 chore: version 1.0.0-rc2, PyPI ready, Codecov, CODEOWNERS
16+
17+
## Pending (human action)
18+
- [ ] Rotate PyPI token (if exposed)
19+
- [ ] Fill Human Review Workbook (docs/HUMAN_REVIEW_WORKBOOK.docx)
20+
- [ ] GitHub: topics, Discussions, Release v1.0.0-rc2
21+
22+
## Next Session Start
23+
1. Load memory: `project_op3_v1_rc2_session_20260410.md`
24+
2. Run: `git log --oneline -5`
25+
3. Run: `make test` (verify nothing broke)

op3/opensees_foundations/builder.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,8 @@ def run_static_condensation(tower_model: "TowerModel") -> np.ndarray:
798798
raise ValueError("need >= 2 spring rows for Winkler integration")
799799
dz = float(z[1] - z[0])
800800

801+
# PHYSICS: Winkler integration — static condensation of distributed springs to 6x6 mudline stiffness
802+
# REVIEW-STATUS: PENDING (awaiting human verification against Randolph & Gourvenec (2011) §5.3)
801803
Kxx = float(np.sum(k) * dz)
802804
Kxrx = float(np.sum(k * z) * dz)
803805
Krxrx = float(np.sum(k * z * z) * dz)

op3/optumgx_interface/step2_gazetas_stiffness.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ def efthymiou_2018_homogeneous(G, nu, R, L, H):
5353
"""
5454
Kv0, Kh0, Kr0 = surface_stiffness(G, nu, R)
5555

56+
# PHYSICS: Gazetas (1991) Table 2 — vertical embedment correction (layered half-space)
57+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
5658
# Vertical
5759
Kv = Kv0 * (1 + 0.4 * (L/R)) * \
5860
(1 + 1.6 * (R/H)) * \
@@ -63,6 +65,8 @@ def efthymiou_2018_homogeneous(G, nu, R, L, H):
6365
(1 + 1.15 * (L/H))**0.65 * \
6466
(1 + 0.7 * (R/H))
6567

68+
# PHYSICS: Gazetas (1991) Table 2 — rocking embedment correction (layered half-space)
69+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
6670
# Rocking
6771
Kr = Kr0 * (1 + L/R)**1.4 * \
6872
(1 + 0.15 * (R/H)) * \

op3/standards/api_rp_2geo.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ def api_pile_stiffness(
4242
L = embedment_m
4343
R = 0.5 * D
4444

45+
# PHYSICS: Gazetas (1991) Eqs. 2-5 — embedded foundation impedances (surface + embedment correction)
46+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
4547
# API formulas (similar to ISO 19901-4 with API correction factors)
4648
K_xx = (8.0 * G * R / (2.0 - nu)) * (1.0 + 0.55 * (L / R) ** 0.85)
4749
K_zz = (4.0 * G * R / (1.0 - nu)) * (1.0 + 0.54 * L / R)
@@ -77,6 +79,8 @@ def gazetas_full_6x6(
7779

7880
K = np.zeros((6, 6))
7981

82+
# PHYSICS: Gazetas (1991) Table 1 — surface foundation static stiffness (half-space solution)
83+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
8084
# Diagonal terms — Gazetas surface foundation
8185
K_x_0 = (8.0 * G * R) / (2.0 - nu)
8286
K_z_0 = (4.0 * G * R) / (1.0 - nu)

op3/standards/cyclic_degradation.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
# Backbone curve
4949
# ---------------------------------------------------------------------------
5050

51+
# PHYSICS: Hardin & Drnevich (1972) Eq. 1 — G/Gmax = 1/(1+(gamma/gamma_ref)^a)
52+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
5153
def hardin_drnevich(gamma: float, gamma_ref: float, a: float = 1.0) -> float:
5254
"""
5355
Modulus reduction G / G_max for shear strain ``gamma``.

op3/standards/dnv_st_0126.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ def dnv_monopile_stiffness(
111111
D = diameter_m
112112
L = embedment_m
113113

114+
# PHYSICS: DNVGL-ST-0126 (2021) §5.5.2 Eq. 5.7 — monopile embedment correction factors
115+
# REVIEW-STATUS: PENDING (awaiting human verification against standard)
114116
# Equivalent stiffness coefficients (DNVGL-ST-0126 §5.5.2 Eq. 5.7)
115117
# Lateral: K_xx = K_yy ~= 8 G D / (2 - nu) with depth correction
116118
depth_factor = 1.0 + 0.5 * np.tanh(L / D - 1.0)
@@ -232,6 +234,8 @@ def dnv_suction_bucket_stiffness(
232234
L = skirt_length_m
233235
R = 0.5 * D
234236

237+
# PHYSICS: Gazetas (1991) — embedded cylindrical foundation impedances for suction bucket
238+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
235239
# Single bucket — Gazetas embedded cylindrical foundation
236240
# Lateral
237241
K_xx_single = (8.0 * G * R / (2.0 - nu)) * (1.0 + 0.55 * (L / R) ** 0.85)

op3/standards/owa_bearing.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ def owa_suction_bucket_stiffness(
6868
L = skirt_length_m
6969
R = 0.5 * D
7070

71+
# PHYSICS: Houlsby & Byrne (2005) Eqs. 5.2-5.5 — suction caisson elastic impedances
72+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
7173
# Houlsby & Byrne (2005) Eq. 5.2-5.5 for embedded caisson
7274
# Lateral
7375
K_xx_single = (4.0 * G * R / (1.0 - nu)) * (1.0 + 1.5 * L / R)

op3/standards/pisa.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
# but for initial elastic stiffness evaluation we only need the linear
8181
# coefficients.
8282

83+
# PHYSICS: Burd et al. (2020) Table 3 — PISA sand calibration coefficients (Dunkirk dense sand)
84+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
8385
PISA_SAND = {
8486
"lateral_p": {
8587
"k_1": 8.64, "k_2": -0.81, # k_p = 8.64 - 0.81 z/D
@@ -107,6 +109,8 @@
107109
},
108110
}
109111

112+
# PHYSICS: Byrne et al. (2020) Table 4 — PISA clay calibration coefficients (Cowden till)
113+
# REVIEW-STATUS: PENDING (awaiting human verification against paper)
110114
# Byrne 2020 clay (Cowden till), second-stage calibration. Table 4.
111115
# Distributed lateral p: k_p = 10.60 - 1.650 * (z/D)
112116
# Curvature: n_p = 0.9390 - 0.03345 * (z/D)

0 commit comments

Comments
 (0)