Metadata-Version: 2.4
Name: geotech-staff-engineer
Version: 5.17.1
Summary: Python toolkit for LLM-based geotechnical engineering agents - 33 analysis modules covering foundations, piles, slopes, structural section/RC/frame analysis, reliability, seismic site response, excavation support, pavement design (AASHTO 1993 / UFC 3-250-01), subsurface characterization (DIGGS/GEF/AGS4), FEM, drawing & profile rendering, and a cited public-domain reference layer.
Author-email: Sean O'Connell <soconnell345@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/soconnell345-geotech/GeotechStaffEngineer
Project-URL: Repository, https://github.com/soconnell345-geotech/GeotechStaffEngineer
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: DISCLAIMER.md
Requires-Dist: numpy>=2.0
Requires-Dist: scipy>=1.13
Requires-Dist: geotech-references>=1.4.0
Requires-Dist: deepagents<0.8,>=0.6.8
Requires-Dist: langchain<1.4,>=1.3
Requires-Dist: langgraph<1.3,>=1.2
Requires-Dist: openai<3
Requires-Dist: langchain-anthropic>=1.4
Requires-Dist: langchain-openai>=1.3
Requires-Dist: typing_extensions>=4.13
Requires-Dist: websockets<16,>=14
Requires-Dist: streamlit>=1.39
Requires-Dist: matplotlib>=3.8
Requires-Dist: jinja2>=3.1
Requires-Dist: plotly>=5
Requires-Dist: openseespy>=3.6
Requires-Dist: pystrata>=0.5
Requires-Dist: eqsig>=1.2
Requires-Dist: pyrotd>=0.6
Requires-Dist: liquepy>=0.3
Requires-Dist: pygef>=0.10
Requires-Dist: gstools>=1.5
Requires-Dist: python-ags4>=0.5
Requires-Dist: SALib>=1.4
Requires-Dist: pystra>=1.3
Requires-Dist: ezdxf>=1.4
Requires-Dist: PyMuPDF>=1.23
Requires-Dist: planlens[raster]>=0.3
Requires-Dist: PyNiteFEA>=3.0
Provides-Extra: plot
Provides-Extra: calc
Provides-Extra: groundhog
Provides-Extra: opensees
Provides-Extra: pystrata
Provides-Extra: seismic-signals
Provides-Extra: liquepy
Provides-Extra: hvsrpy
Provides-Extra: gstools
Provides-Extra: salib
Provides-Extra: swprocess
Provides-Extra: pystra
Provides-Extra: dxf
Provides-Extra: interactive
Provides-Extra: pdf
Provides-Extra: raster
Provides-Extra: subsurface
Provides-Extra: pygef
Provides-Extra: ags4
Provides-Extra: pydiggs
Requires-Dist: pydiggs>=0.1; extra == "pydiggs"
Provides-Extra: structural
Provides-Extra: deep
Provides-Extra: webapp
Provides-Extra: full
Dynamic: license-file

# GeotechStaffEngineer

**A Python toolkit that turns the geotechnical staff engineer's repertoire into composable, machine-callable methods — wraps them in a probabilistic variability engine — and drives them with an engine-agnostic LLM agent.**

30 analysis modules · 21 digitized references · FOSM/PEM/Monte-Carlo/FORM reliability · validated against published benchmarks.

> 📊 **Rich visual overviews** (open in a browser): [Project overview](docs/overview.html) · [Agentic retrieval developer guide](docs/agentic_retrieval_devguide.html)

---

## ⚠️ Professional-use disclaimer

**This toolkit is an analysis and research aid — a multiplier for a qualified engineer's judgment, not a replacement for it, and not a design deliverable.** It runs industry-standard methods and an LLM agent that drives them, but it does not know your site and cannot exercise engineering judgment. Every input, assumption, method choice, and result **must be independently reviewed by a licensed professional engineer familiar with the site** before it is relied upon; LLM-agent output in particular is a starting point for review, never a final basis for design. Using this software creates **no engineer-of-record relationship**. Validation covers only the documented benchmark cases in [`validation_examples/RESULTS.md`](validation_examples/RESULTS.md); all units are SI. Provided under the MIT License **"AS IS", without warranty of any kind**.

**→ Read the full terms in [`DISCLAIMER.md`](DISCLAIMER.md).**

---

## Soil is uncertain. So you don't calculate once — you calculate repeatedly until the problem is understood.

Geotechnical engineering is the practice of building **on** and **in** the ground: foundations, retaining walls, slopes, excavations, embankments. Unlike a steel beam with a certified strength, the geotechnical engineer's material is **the earth itself** — heterogeneous, layered, partly saturated, and sampled at only a handful of points across an entire site.

Because the ground is **variable and only partly known**, a single number is never the answer. Understanding a geotechnical problem means understanding *how the answer moves as the inputs move*. That's what this project is built around.

### What a geotechnical engineer actually does

| Step | Activity | Reality |
|------|----------|---------|
| **1 · Characterize** | Drill borings, push CPT cones, run lab tests | A sparse, noisy picture of strength, stiffness, and groundwater — never the whole truth |
| **2 · Idealize** | Collapse the data into a layered soil profile | Design values of φ, c, γ, water table — each an *estimate with a spread* |
| **3 · Analyze** | Run the method (bearing capacity, settlement, pile capacity, slope stability) | A chained assortment of industry-standard formulas, empirical and numerical methods |
| **4 · Check & revise** | Compare against the design requirements; vary assumptions; re-run | Loop until the design is robust *across* the uncertainty |

Steps 3 and 4 are repeated calculations across plausible subsurface and loading conditions. The agent helps the engineer understand the range and *spread* of answers.

### In geotechnical engineering, the true answer is a distribution

- **Parameter uncertainty** — design properties carry coefficients of variation (COV) of 10–40%, far larger than structural materials.
- **Spatial variability** — soil changes boring to boring; a footing averages over its footprint, a long slope samples many weak and strong zones. Scale matters.
- **Model & scenario sweeps** — drained or undrained? Water table high or low? Seismic case? Each is another axis to run the calculation along.

Done by hand, that exploration gets truncated — a couple of cases and a lot of conservatism to cover the gaps. Done by **machine**, the same deterministic method runs ten thousand times across the full statistical picture and returns a **reliability index β** and a **probability of failure P_f** instead of a lone factor of safety.

### Computers have always amplified the engineer

Slide rules and design charts → spreadsheets and FEM → scripting and Monte Carlo → **LLM agents**. Every tool in this lineage did the same thing: it let one engineer explore more of the problem in the time they had. This project is the next step — *not a replacement for judgment, but a multiplier for it.* Take the methods a staff engineer uses, make every one a clean Python function that returns structured data, wrap the variability tooling around them, and put a reasoning agent on top.

---

## Architecture

One stack, layered so each concern stays independent. Analysis modules never import each other — they all speak one shared `SoilProfile`. The reliability and sensitivity engines wrap *any* deterministic method as a callable. The reference library and the agent harness sit on top.

```mermaid
flowchart TB
    ENG["Engineer asks in natural language"]

    subgraph AGENT["Agent harness - engine-agnostic LLM driver"]
        FA["funhouse_agent: GeotechAgent, dispatch, vision"]
        FD["foundry wrappers: 48 standalone tool agents"]
        LIB["9 library agents"]
        GP["geo_project: staged human-gated setup"]
    end

    subgraph VAR["Variability engine - wraps any deterministic method, runs it thousands of times"]
        REL["reliability: FOSM, PEM, Monte Carlo, FORM to beta and Pf"]
        COV["cov_database and spatial: published COV, Vanmarcke averaging"]
        SENS["salib and pystra: Sobol/Morris, structural reliability"]
    end

    subgraph DET["Deterministic analysis - 30 modules, dataclass I/O, no cross-imports"]
        F["foundations, deep foundations, earth retention"]
        S["slope, FEM, CAD"]
        SE["seismic, characterization"]
    end

    SPINE["geotech_common: SoilProfile spine - one type every module speaks"]
    REF["geotech-references: 21 digitized standards - DM7, GEC, UFC, FHWA"]
    GROUND["Subsurface reality: borings, CPT, lab tests"]

    ENG --> AGENT
    AGENT --> VAR
    VAR -->|run the calc N times| DET
    DET --> SPINE
    AGENT -.->|cites| REF
    GROUND --> SPINE

    classDef agent fill:#1a1326,stroke:#c8a0ff,color:#e8edf6
    classDef var fill:#241804,stroke:#ffb86b,color:#e8edf6
    classDef det fill:#0d1622,stroke:#5cc8ff,color:#e8edf6
    classDef spine fill:#0e1f16,stroke:#7df0c0,color:#e8edf6
    classDef ref fill:#130f1c,stroke:#c8a0ff,color:#e8edf6
    classDef ground fill:#0e1626,stroke:#6b778c,color:#9aa7bd
    class FA,FD,LIB,GP agent
    class REL,COV,SENS var
    class F,S,SE det
    class SPINE spine
    class REF ref
    class GROUND ground
```

- **Why a shared spine** — one `SoilProfile` type means modules compose without knowing about each other, and an agent learns one way to describe the ground.
- **Why no cross-imports** — analysis modules are independent, testable leaves; the routing that *combines* them lives in the agent layer.
- **Why variability is its own layer** — it's orthogonal. `reliability` doesn't know what bearing capacity *is*; it knows how to take any callable `g(values)` and characterize how its output scatters. Wrap once, apply everywhere.

---

## ★ The variability engine — the same calculation, thousands of times

This is the heart of "explore the problem, don't point-estimate it." The `reliability` module turns any deterministic analysis into a probabilistic one. Declare the uncertain inputs as random variables, hand it a performance function `g(values) → FOS or margin`, pick an engine — get back the reliability index **β** and probability of failure **P_f**.

```python
from reliability import RandomVariable, monte_carlo, fosm, cov_guidance
from reliability.wrappers import bearing_capacity_reliability

# 1 · Uncertain inputs — pull a defensible COV straight from the literature
cov_guidance("friction_angle")        # → Duncan 2000 / Phoon-Kulhawy guidance
phi   = RandomVariable("phi",   mean=32, cov=0.10, dist="lognormal")
c     = RandomVariable("c",     mean=8,  cov=0.30, dist="lognormal")
gamma = RandomVariable("gamma", mean=18, cov=0.07)

# 2 · The performance function: the DETERMINISTIC module, called per sample
def g(v):                              # v = {"phi":.., "c":.., "gamma":..}
    res = bearing_capacity_analysis(phi=v["phi"], c=v["c"], gamma=v["gamma"], width=2.0)
    return res["factor_of_safety"]     # scalar margin: g >= 1 is "safe"

# 3 · Pick an engine — all four share the same g() contract
mc   = monte_carlo(g, [phi, c, gamma], n=50_000, target=1.0)
fast = fosm(g, [phi, c, gamma])        # first-order, no sampling

print(mc.beta, mc.pf)   # reliability index & probability of failure — the real deliverable
```

| Engine | Cost | What it does |
|--------|------|--------------|
| **FOSM** | cheap | First-Order Second-Moment — propagates means & variances; instant β |
| **PEM** | robust | Rosenblueth Point Estimate — evaluates g() at ± points; handles non-linearity without a derivative |
| **Monte Carlo** | exact-ish | Sample the joint distribution N times, count failures; correlations and all |
| **FORM** | efficient | Native first-order reliability — finds the design point; β at a fraction of MC's calls |

- **`cov_database`** — a queryable knowledge base of published coefficients of variation (Duncan 2000, TC304, Phoon & Kulhawy) keyed by soil property. Ask, don't assume.
- **`spatial`** — Vanmarcke spatial averaging reduces variance over the volume a structure actually loads (`scale_of_fluctuation_guidance`, `variance_reduction`).
- **`salib_agent`** — global sensitivity (Sobol, Morris): *which* input drives the variance? Together they map a problem's full depth and the factors that govern it.

`slope_stability` and the reliability wrappers (`bearing_capacity_reliability`, `axial_pile_reliability`, `slope_reliability`) ship the probabilistic path out of the box.

---

## Module inventory

Thirty analysis modules grouped by discipline, plus the shared layers. Native modules implement the method directly; "agent" modules wrap a trusted third-party library behind the same dict-based API. All units are SI (m, kPa, kN, degrees); every module returns dataclasses with `.summary() → str` and `.to_dict() → dict`.

| Domain | Modules | What they compute |
|--------|---------|-------------------|
| **foundations** | `bearing_capacity` · `settlement` | Shallow footing capacity (Vesic/Meyerhof/Hansen, two-layer); consolidation + immediate settlement |
| **deep foundations** | `axial_pile` · `lateral_pile` · `pile_group` · `drilled_shaft` · `wave_equation` · `downdrag` | Driven & bored pile capacity, p-y lateral analysis, rigid-cap groups, Smith wave-equation drivability, neutral-plane downdrag |
| **earth retention** | `sheet_pile` · `soe` · `retaining_walls` · `ground_improvement` | Cantilever/anchored walls, support-of-excavation, cantilever & MSE walls, aggregate piers / wick drains / vibro |
| **slope · FEM · CAD** | `slope_stability` · `fem2d` · `dxf_import` · `dxf_export` · `planlens.pdf` | Rigorous limit-equilibrium (GLE/M-P, Bishop/Spencer/Janbu) + probabilistic FOS; 2D plane-strain FEM with strength reduction; geometry I/O |
| **document review** | [`planlens`](https://pypi.org/project/planlens/) (separate package, installed as a dependency) | Any PDF or image as review-ready data for the agent: a page map and the document's structure (from the pages' own headers, footers and printed numbering), text with exact locations, tables, the review markups (who said what, where it points), AutoCAD hidden text, contact sheets; plus drawing geometry and annotation constructs (leaders, dimensions, callouts). The agent reads first and is told when to look. |
| **seismic** | `seismic_geotech` · `opensees_agent` · `pystrata_agent` · `liquepy_agent` · `seismic_signals_agent` | Site class, M-O pressures, liquefaction triggering (B&I-2014 / NCEER), 1D site response, ground-motion processing |
| **structural** | `section_props_agent` · `concrete_props_agent` · `pynite_agent` | Cross-section properties (exact polygon integration + closed-form torsion), RC section capacity/cracked properties (ACI strain compatibility), elastic frame + continuous-beam analysis |
| **characterization** | `subsurface_characterization` · `gstools_agent` | DIGGS/GEF/AGS4 data I/O + plots, geostatistical kriging/random fields |
| **variability** | `reliability` · `salib_agent` · `pystra_agent` | FOSM/PEM/MC/FORM + COV database + spatial averaging; Sobol/Morris sensitivity; structural FORM/SORM/MC |
| **shared / setup** | `geotech_common` · `geo_project` · `calc_package` | SoilProfile spine + checks + adapters + plots; staged human-gated model setup; calculation-package report generation |
| **references** | `geotech-references` (21) | Digitized tables/figures/equations + searchable chapter text from DM7, FHWA GEC series, UFC, FHWA standards |

### Library wrapper agents

Each wraps a third-party geotechnical library behind a dict-based API for LLM tool use:

| Module | Library | Purpose |
|--------|---------|---------|
| `opensees_agent` | OpenSeesPy | PM4Sand cyclic DSS, 1D site response |
| `pystrata_agent` | pystrata | 1D equivalent-linear site response |
| `seismic_signals_agent` | eqsig + pyrotd | Earthquake signal processing |
| `liquepy_agent` | liquepy | Boulanger & Idriss (2014) liquefaction triggering — CPT (LPI/LSN/LDI) and SPT |
| `gstools_agent` | gstools | Geostatistical kriging and random fields |
| `salib_agent` | SALib | Sobol and Morris sensitivity analysis |
| `pystra_agent` | pystra | FORM/SORM/Monte Carlo reliability |

> The former `pygef_agent`, `ags4_agent`, and `pydiggs_agent` wrappers were folded into `subsurface_characterization` as optional, dependency-backed format adapters — one module now covers ingest + validate + visualize across DIGGS, GEF/BRO-XML, and AGS4.

---

## Engineering rigor

An agent that confidently returns a wrong bearing capacity is worse than useless. The project's discipline is what makes the outputs citable:

- **One unit system, one I/O shape** — everything is SI; every `analyze_*()` returns a dataclass with `.summary()` (human/agent reading) and `.to_dict()` (machine/JSON).
- **Validated against the literature** — flagship modules carry a `VALIDATION.md` with worked checks: `slope_stability` vs Fredlund & Krahn 1977 / ACADS / Duncan; `fem2d` vs Griffiths & Lane and the Prandtl solution (~2%); lateral pile vs a COM624P oracle suite.
- **Tests as a safety net** — each module ships a pytest suite sized to its risk (e.g. `slope_stability` 384, `fem2d` 353, `geotech_common` 288; the reference library alone 3,529). Changes regress against textbook answers.
- **A reviewer in the loop** — the agent can run a second, reference-scoped pass that checks methodology, parameter ranges, and required safety factors against the standards.

---

## Installation

```bash
# the whole stack: analysis modules, reference library, deep agent, webapp
pip install geotech-staff-engineer

# (the old extra names -- [deep], [full], [plot] ... -- are empty aliases kept
# only so older install commands keep working; they add nothing)
```

## Quick start — three ways in

The same validated methods are reachable at three altitudes.

**A · Deterministic** — import a module, get a dataclass back:

```python
from bearing_capacity import Footing, SoilLayer, BearingSoilProfile, BearingCapacityAnalysis

footing = Footing(width=2.0, length=10.0, depth=1.5, shape="strip")
layer   = SoilLayer(friction_angle=30.0, cohesion=10.0, unit_weight=18.0, thickness=10.0)
profile = BearingSoilProfile(layer1=layer, gwt_depth=5.0)

result = BearingCapacityAnalysis(footing=footing, soil=profile).compute()
print(result.summary())     # readable report
result.to_dict()            # JSON-ready for an agent or a calc package
```

**B · Probabilistic** — the same calc, wrapped to return the distribution:

```python
from reliability.wrappers import bearing_capacity_reliability
out = bearing_capacity_reliability(variables=spec, engine="monte_carlo", n=50_000)
out.beta, out.pf            # the answer's shape, not one point on it
```

**C · Agentic** — describe the problem, let the agent run the methods & cite the standards:

```python
from funhouse_agent import GeotechAgent, NativeToolEngine
agent = GeotechAgent(genai_engine=NativeToolEngine(fh_prompter))   # Claude / Funhouse Prompter / OpenAI-native

agent.ask("2 m strip footing, 1.5 m deep, sand phi=30, c=10, water at 5 m. "
          "Bearing capacity and FOS — and how sensitive is it to phi? Cite the method.")
# → picks bearing_capacity, runs it, sweeps phi, consults DM7/GEC, returns a cited answer
```

At every altitude it's the *same* validated method underneath. The deterministic call is the atom; the variability engine runs that atom across uncertainty; the agent decides which atoms to run and reads the standards back to you.

## Optional extras

| Extra | Libraries |
|-------|-----------|
| `plot` | matplotlib |
| `calc` | jinja2 |
| `opensees` | openseespy |
| `pystrata` | pystrata |
| `seismic-signals` | eqsig, pyrotd |
| `liquepy` | liquepy |
| `gstools` | gstools |
| `salib` | SALib |
| `pystra` | pystra |
| `subsurface` | pygef, python-ags4, pydiggs (subsurface_characterization format adapters) |
| `pygef` / `ags4` / `pydiggs` | aliases for the individual format-adapter libraries |
| `dxf` | ezdxf |
| `full` | All of the above |

## Unified liquefaction

Liquefaction triggering is exposed to the agent through a single `liquefaction` tool that auto-routes by input type and method:

- **CPT** input (cone resistance `q_c` / sleeve friction `f_s`) → Boulanger & Idriss (2014) CPT procedure via `liquepy`, with LPI / LSN / LDI indices.
- **SPT** input (`N160` blow counts) → Boulanger & Idriss (2014) by default (`method="bi2014"`), or the legacy NCEER / Youd et al. (2001) simplified procedure via `method="nceer2001"` for code-compliance work that cites it.

B&I-2014 is the default for both. The underlying per-module functions remain available directly: `liquepy_agent.analyze_cpt_liquefaction` / `analyze_spt_liquefaction` (B&I-2014) and `seismic_geotech.evaluate_liquefaction` (NCEER/Youd-2001 SPT).

## Related packages

[geotech-references](https://pypi.org/project/geotech-references/) — Digitized NAVFAC DM7 and FHWA GEC reference library (installed automatically as a dependency). For how the agent searches and cites it — full-text search, figure + vision read-off, and a scoped consult sub-agent — see the [agentic retrieval developer guide](docs/agentic_retrieval_devguide.html).

[planlens](https://pypi.org/project/planlens/) — Review-ready data from AEC documents for LLMs (installed automatically as a dependency): the whole-document layer behind the agent's `open_document` / `read_document` / `document_markups` tools and the drawing-geometry layer behind its drawing tools. Independent of this package; usable from any LLM harness.

## License

MIT
