Initial commit: establish deterministic rod-string solver stack.

Set up the C solver core, Node API orchestration, TS GUI workflow, and engineering documentation with cleaned repo hygiene for private Git hosting.

Made-with: Cursor
This commit is contained in:
2026-04-16 21:59:42 -06:00
commit 725a72a773
83 changed files with 14687 additions and 0 deletions

213
Agents/COMPUTE_PLAN.md Normal file
View File

@@ -0,0 +1,213 @@
# Compute handoff — Rods Cursor
**Owner:** Agent team
**Status:** Active
**Last updated:** 2026-04-16
**Canonical math:** [MATH_SPEC.md](MATH_SPEC.md)
**Agent rules:** [AGENTS.md](../AGENTS.md) at repo root
**Reference bibliography:** [references/papers/README.md](../references/papers/README.md)
---
## 1. Session context
Math-first rod-string / dynamometer stack:
- **C (`solver-c`)** — Authoritative FDM + FEA + diagnostic transfer + trajectory preprocess. **JSON on stdin** to `solver_main` / `solver_fea_main` (`schemaVersion: 2`).
- **Node (`solver-api`)** — XML → SI model, surface-card QA, orchestration, `comparison` / `verbose` / `pumpMovement`, `schemaVersion` in responses.
- **GUI (`gui-ts`)** — Workflow / plots, XML round-trip editor, engineering checks, and 3D wellbore visualization.
User goals: SROD-like transparency, measured card → downhole + pump movement, FDM vs FEA comparison, no invented physics.
---
## 2. Repository map
| Path | Role |
|------|------|
| `solver-c/src/solver.c` | FDM predictive + gravity/buoyancy + variable \(EA\rho\) + side-load Coulomb |
| `solver-c/src/solver_fea.c` | FEA predictive + Rayleigh damping + diagnostic bisection (Eisner-style) |
| `solver-c/src/solver_diagnostic.c` | Diagnostic FDM from surface card |
| `solver-c/src/trajectory.c` | Survey → curvature / inclination on rod grid |
| `solver-c/src/json_stdin.c` | stdin JSON → `SolverInputs` |
| `solver-api/src/xmlParser.js` | Parse + **SI** normalization |
| `solver-api/src/solverClient.js` | Build JSON, run C |
| `solver-api/src/cardQa.js` | Surface card validation |
| `solver-api/src/app.js` | HTTP, extended `comparison`, `validate-card` |
| `data/cases/base-case.xml` | Canonical case |
| `data/golden/default.solve.sha256` | Golden fingerprint for `/solve/default` |
---
## 3. Status vs MATH_SPEC (gap table)
| Item | MATH_SPEC § | Code status |
|------|-------------|-------------|
| Variable \(EA\) FDM | §13 | **Done** — per-node `area_m2`, `modulus_pa`, `density_kg_m3` |
| Gravity + buoyancy | §1 | **Done** — distributed \(f = \rho g A - \rho_f g A\) (simplified annulus = rod area) |
| Explicit FD + CFL | §3 | **Done**`verbose.numerics` |
| 3D survey / curvature | §5 | **Partial**`trajectory.c` resamples MD/inc/azi; full Araujo Eqs. 1418 system = future refinement |
| Lukasiewicz lateral PDE | §4 | **Partial** — side load from \(T,\kappa,\phi\) proxy + Coulomb (`heuristic` tag in verbose) |
| Valve state machine | §7 | **Partial** — simplified phase + `gasInterference` flag from load plateau heuristic |
| Diagnostic FDM in C | §7 | **Done**`solver_diagnostic.c` |
| Diagnostic FEA + iteration | §67 | **Done** — bisection on bottom load in `solver_fea.c` when `workflow=diagnostic` |
| Rayleigh \(\alpha,\beta\) from XML damping | §2 | **Done** — tied to rod length + damping factors |
| Multi-material taper | §1 | **Done**`RodTypeArray` / modulus arrays in JSON |
| Fourier analytical baseline | §3 | **Deferred** |
| Full tubetube contact (Eisner) | §6 | **Deferred** |
---
## 4. API (quick reference)
```http
POST /solve
Content-Type: application/json
{
"xml": "<INPRoot>...</INPRoot>",
"solverModel": "fdm|fea|both",
"workflow": "predictive|diagnostic",
"surfaceCard": { "position": [], "load": [], "time": [] },
"options": { "schemaVersion": 2 }
}
```
- `GET /solve/default` — predictive only; supports `?solverModel=`.
- `POST /solve/validate-card` — QA only (no solve).
- Response: `schemaVersion`, `units: "SI"`, `solver`, `solvers?`, `comparison` (extended), `pumpMovement?`, `verbose`, `runMetadata`.
---
## 5. Runbook
```bash
make test
./solver-c/test_solver
cd solver-api && npm test
# Docker
docker compose up -d --build
make smoke
```
`docker-compose.yml` gcc lines must list all `solver-c/src/*.c` objects used by `main.c` / `main_fea.c`.
---
## 6. Deferred (explicit)
| Topic | Notes |
|-------|--------|
| Full **Costa / SPE-173970** 3D wave with \(K_1,K_2\) lateral load PDE in C | Currently curvature + side-load **proxy**; implement from paper, not ad hoc |
| **Torsion** | Not in current four-paper backbone |
| **Pumping-unit kinematics** (Svinos tables, crank motion from `PumpingUnitID`) | Harmonic default; unit geometry unused |
| **Inverse calibration** | Fit damping / friction to measured downhole card |
| **Fourier** analytical diagnostic | Optional `comparison.fourier` |
| **GUI** 3D survey + layout | **Partial done** — Results tab includes 3D projected wellbore + rod/pump overlay + DLS contour; not a full 3D engine (no camera controls / mesh terrain yet) |
| **GUI diagnostic workflow** | Tabbed UI ships predictive solve end-to-end; diagnostic requires surface-card upload path in Kinematics (calls `POST /solve/validate-card` + `POST /solve` with `workflow=diagnostic`) — not wired in this pass |
| **GUI Pump / Fluid / Kinematics first-class mapping** | Tabs render editable fields but rely on `rawFields` round-trip rather than dedicated serializer logic; audit once solver-api adds explicit fields for `PumpFillageOption`, pumping-unit kinematics, etc. |
| **GUI fatigue / API RP 11BR table** | Backend does not emit a fatigue payload yet; surface in Results tab when `solver.fatigue` exists |
---
## 6.1 GUI checks/visualization shipped
- Fixed engineering gate in Solver tab:
- run blocked when `|PumpDepth - sum(TaperLengthArray)| > 15 m`.
- survey MD monotonicity and minimum station-count checks.
- Fixed DLS bad-section threshold:
- warnings + 3D contour use `15 deg/100` as the "bad section" limit.
- Results tab now shows:
- uPlot dynacard overlays,
- 3D projected wellbore with rod gradient and pump marker,
- interactive 3D view controls (rotate, pan, zoom, perspective/orthographic toggle, reset),
- highlighted bad-DLS segments,
- trajectory analytics table with row↔3D segment cross-highlight,
- side-load overlay mode (when `solver.profiles.sideLoadProfile` is available),
- pump-placement diagnostics panel + navigation actions,
- export actions (3D SVG, 3D PNG, summary JSON).
- keyboard-accessible trajectory segment selection (`Enter`/`Space`) and clear-highlight control.
- Kinematics/Solver workflow now supports diagnostic execution end-to-end in GUI:
- measured card paste input (`position,load` rows),
- `POST /solve/validate-card` QA call from Kinematics tab,
- diagnostic solve payload wiring (`workflow=diagnostic`, `surfaceCard`),
- solve options include profile generation for visualization overlays.
---
## 7. Jump table
| Task | Start |
|------|--------|
| FDM numerics | `solver-c/src/solver.c` |
| FEA + diagnostic bisection | `solver-c/src/solver_fea.c` |
| Diagnostic FDM | `solver-c/src/solver_diagnostic.c` |
| Trajectory | `solver-c/src/trajectory.c` |
| JSON CLI | `solver-c/src/json_stdin.c`, `main.c`, `main_fea.c` |
| SI + XML | `solver-api/src/xmlParser.js` |
| Run C | `solver-api/src/solverClient.js` |
| Card QA | `solver-api/src/cardQa.js` |
| HTTP | `solver-api/src/app.js` |
| Tests | `solver-api/tests/api.test.js`, `solver-c/tests/test_solver.c` |
---
## 8. Quality Program (next execution block)
This section is the execution plan for the next pass, optimized for "feature-rich but solid".
### 8.1 Priority 1 — Correctness gates first
- Build a field-sensitivity harness (per mapped input field, ±1% perturbation).
- Enforce invariants in solver outputs:
- finite values everywhere,
- gas fraction bounds,
- physically valid valve-state transitions,
- profile array length consistency.
- Expand deterministic goldens beyond base case.
**Acceptance gate:** no merge if sensitivity/invariant tests fail.
### 8.2 Priority 2 — Solver fidelity
- Reduce remaining heuristic terms toward equation-backed Costa/Araujo + Lukasiewicz formulations.
- Harden valve/gas state model transitions with explicit edge-case fixtures.
- Add stability fallback behavior and numerical-health reporting.
**Acceptance gate:** documented equation coverage increases; no stability regressions.
### 8.3 Priority 3 — Validation depth
- Add cross-model agreement matrix (FDM vs FEA) across canonical cases.
- Add synthetic/analytical sanity cases where expected trends are known.
- Track residual drift trends over commits.
**Acceptance gate:** tolerance matrix passes for all canonical cases.
### 8.4 Priority 4 — Contract hardening
- Keep `schemaVersion: 2` additive contract stable by default.
- Enforce option-gated heavy payloads (`profiles`, `diagnostics`, `fourier`).
- Add traceability metadata endpoint/payload support for GUI and audits.
**Acceptance gate:** backward-compat tests pass on default endpoints.
### 8.5 Priority 5 — CI/release readiness
- Add sanitizer runs (ASan/UBSan) for C paths.
- Add runtime/performance budgets on representative cases.
- Enforce quality artifact generation in CI (comparison summaries + drift reports).
**Acceptance gate:** CI quality lane green.
### 8.6 Multi-agent execution split
- Agent A: solver numerics/fidelity.
- Agent B: GUI integration + import/export + rendering.
- Agent C: verification harness + CI guardrails + independent audit.
---
*Extend §3 and §8 together whenever milestones ship.*

133
Agents/MATH_SPEC.md Normal file
View File

@@ -0,0 +1,133 @@
# Math specification — literature backbone
**Status:** Living document. Every implemented term should trace to a citation below or to an explicit `heuristic` calibration note in code + `docs/engineering/validation.md`.
**Primary references:** see `references/papers/README.md` for citation details and source links.
- Romero, A., and Almeida, A. R. (2014). *A Numerical Sucker-Rod Pumping Analysis Tool*. SPE Artificial Lift Conference - Latin America and the Caribbean. [SPE-169395-MS](https://doi.org/10.2118/169395-MS)
- Everitt, T. A., and Jennings, J. W. (1992). *An Improved Finite-Difference Calculation of Downhole Dynamometer Cards for Sucker-Rod Pumps*. SPE Production Engineering. [SPE-18189-PA](https://doi.org/10.2118/18189-PA)
- Araujo, O., et al. (SPE-173970). *3D Rod String Dynamics in Deviated Wells* (minimum-curvature and coupled dynamics reference used for trajectory coupling).
- Eisner, B., Langbauer, C., and Fruhwirth, R. (2022). *A finite element approach for dynamic sucker-rod diagnostics* (Newmark + Rayleigh + diagnostic iteration basis).
- Lukasiewicz, H. (as summarized in Eisner et al.) coupled axial/lateral force balance for deviated rod strings.
---
## 1. Gibbs one-dimensional damped wave (vertical / uniform rod)
**Romero & Almeida — Eq. (2)** (viscous damped wave, constant \(A,E,\rho\)):
\[
\frac{\partial^2 u}{\partial t^2} = a^2 \frac{\partial^2 u}{\partial x^2} - \varsigma \frac{\partial u}{\partial t}
\]
with \(a^2 = E/\rho\) (wave speed) and \(\varsigma\) viscous damping coefficient per unit mass (paper uses lumped fluid damping narrative).
**Variable cross-section (Everitt & Jennings — Eq. 2 form)** after multiplying through by \(\rho A\); axial stiffness gradient:
\[
\frac{\partial}{\partial x}\left( EA \frac{\partial u}{\partial x} \right) = \rho A \frac{\partial^2 u}{\partial t^2} + c \rho A \frac{\partial u}{\partial t} - f_{\text{body}}
\]
where \(f_{\text{body}}\) collects distributed **weight and buoyancy** along the rod (gravity along tangent; buoyancy from fluid — **Lukasiewicz** axial force balance in Eisner Eq. (2) discussion / Lukasiewicz coupled model referenced in Eisner).
**Implementation note:** Code uses discrete \(E_i, A_i, \rho_i\) per node or segment, harmonic or measured surface \(u(0,t)\), and bottom boundary coupling (pump / valve / spring-damper per roadmap).
---
## 2. Damping conventions
- **Gibbs dimensionless damping** \(\nu\): related to decay rate; Romero cites \(\varsigma\) proportional to velocity; Eisner Eq. (1) uses \(\frac{\pi a \nu}{2L}\frac{\partial u}{\partial t}\) form for vertical damped wave.
- **Rayleigh damping (FEA, Eisner):** \(\mathbf{C} = \alpha \mathbf{M} + \beta \mathbf{K}\) for bar elements.
- **XML factors:** `UpStrokeDampingFactor`, `DownStrokeDampingFactor`, `NonDimensionalFluidDamping` modulate effective \(\gamma\) or \(\alpha,\beta\) per phase (mapped in solver; see code comments).
---
## 3. Explicit finite-difference stencil (diagnostic / deviated extension)
**Everitt & Jennings — Eq. (3)** (conceptual explicit FD recursion transferring displacements downhole from surface card). The paper gives a five-point relation in \((i,j)\) space (space index \(i\), time \(j\)) with coefficients involving \(a\), \(c\), \(\Delta t\), \(\Delta x\), and \(EA\).
**Variable \(EA\):** harmonic mean or segment fluxes:
\[
\text{flux}_{i+\frac12} = E_{i+\frac12} A_{i+\frac12} \left( u_{i+1} - u_i \right)
\]
Laplacian-like term formed from \(\partial/\partial x (EA \partial u/\partial x)\) discretization (matches current diagnostic JS prior to C port).
**CFL:** explicit wave requires \(\Delta t \le \text{CFL} \cdot \Delta x / a_{\max}\) with \(a_{\max} = \max \sqrt{E/\rho}\). Code clamps effective CFL (see `verbose.numerics.cflEffective`).
---
## 4. Deviated wells — coupled axial / lateral (reference)
**Lukasiewicz (via Eisner Eqs. (2)(3))** — force balance along rod tangent and normal; includes \(\rho g A \cos\phi\), viscosity term \(\nu\), Coulomb \(\mu N\), curvature \(R\), and lateral equilibrium.
**Current implementation:** distributed **side load** \(N_i\) and inclination-aware **Coulomb friction** \(F_{f,i} = \mu_{\text{eff}} N_i \operatorname{sgn}(v_i)\) are computed per node and injected into FDM/diagnostic/FEA updates. API exposes `profiles.sideLoadProfile` and `profiles.frictionProfile` when `options.enableProfiles=true`.
---
## 5. Three-dimensional trajectory (SPE-173970)
**Araujo et al. — Eqs. (5)(24):** minimum-curvature method between survey stations: unit tangent, curvature angle \(\gamma_i\), radius \(r_{c,i}\), binormal, center of curvature, position propagation \(R(s_{i+1})\), and interpolation of any MD \(s\) within a segment.
**Implementation:** `solver-c/src/trajectory.c` uses minimum-curvature style tangent interpolation and exports node-wise \(\kappa(s)\), inclination, and azimuth on the rod grid for side-load/friction coupling and `trajectory3D` output.
---
## 6. Dynamic 1D bar FEM (Eisner et al.)
- **Bar stiffness / mass:** consistent element \(K_e\), \(M_e\) for linear shape functions.
- **Newmark-β** (\(\beta=\frac14\), \(\gamma=\frac12\)) for transient axial dynamics.
- **Bottom BC:** spring-damper + friction; diagnostic mode adds **iterative plunger load** adjustment so that computed top reaction matches measured polished load (Eisner Fig. 4 principle — restart / bisection per time step).
---
## 7. Boundary conditions
| Mode | Surface | Bottom |
|------|---------|--------|
| **Predictive** | Harmonic \(u(0,t)\) (Romero **Eq. (4)** style crank motion) or measured surrogate | Pump: spring-damper + friction + valve-state pressure balance; gas fraction inferred from chamber state |
| **Diagnostic** | Measured \(u(0,t)\) and \(F(0,t)\) from dynamometer card (Everitt) | Same pump BC; FEA adjusts unknown plunger load and reports valve/gas timeline |
**Surface card QA (Eisner narrative):** ≥ 75 samples recommended for Fourier-style tools; we enforce minimum samples and cycle checks in API (`POST /solve/validate-card`).
---
## 8. Outputs (API / solver)
- Polished and downhole **cards** \((x, F)\).
- **Pump movement:** plunger position series, velocity, stroke, period.
- **Optional profiles:** `stressProfile`, `sideLoadProfile`, `trajectory3D` (when `schemaVersion >= 2`).
- **Comparison:** FDM vs FEA peak deltas + point-wise residuals + optional Fourier analytical baseline (`comparison.fourier` when enabled).
---
## 9. Symbols (SI internal)
| Symbol | Unit | Meaning |
|--------|------|---------|
| \(u\) | m | Axial displacement |
| \(F\) | N | Axial force (tension positive) |
| \(E\) | Pa | Youngs modulus |
| \(A\) | m² | Cross-sectional area |
| \(\rho\) | kg/m³ | Rod density |
| \(\phi\) | rad | Inclination from vertical |
| \(\kappa\) | 1/m | Path curvature |
---
## 10. Implementation quality rules (for next execution)
- Every newly introduced solver term must be tagged as one of:
- `equation-backed` (with paper/equation reference),
- `heuristic` (with rationale + planned replacement).
- No silent heuristic drift: if a coefficient changes, update validation fixtures and notes.
- Any new field wired into equations must be reflected in `docs/engineering/field-traceability.md`.
- Any new coupled term must include at least:
- one unit-scale numerical test,
- one integration case assertion,
- one regression guard.
---
*End of math spec backbone. Extend with equation numbers from PDFs as features land.*