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
239 lines
9.5 KiB
Markdown
239 lines
9.5 KiB
Markdown
# Rods Cursor — Rod-string solver (math-first)
|
|
|
|
Deterministic **C** numerical core (FDM + FEA), **Node** API for XML and orchestration, **TypeScript** GUI for workflow. See **[AGENTS.md](AGENTS.md)** for agent rules and **[Agents/MATH_SPEC.md](Agents/MATH_SPEC.md)** for equations and paper citations.
|
|
|
|
## Repository layout
|
|
|
|
| Directory | Purpose |
|
|
|-----------|---------|
|
|
| `solver-c/` | C: damped-wave FDM, dynamic bar FEM, diagnostic transfer, trajectory preprocess, **JSON stdin** drivers |
|
|
| `solver-api/` | Express: `POST /solve`, `GET /solve/default`, `POST /case/parse`, `POST /solve/validate-card`, XML → SI |
|
|
| `gui-ts/` | Vite + React tabbed case editor + uPlot dynacards |
|
|
| `data/cases/` | `base-case.xml` and regression inputs |
|
|
| `data/golden/` | Golden SHA-256 fingerprint for default solve regression |
|
|
| `Agents/` | `MATH_SPEC.md`, `COMPUTE_PLAN.md` (handoff) |
|
|
| `docs/engineering/` | Architecture, schema, units, validation |
|
|
| `references/papers/` | Literature citations and access notes for the solver math backbone |
|
|
|
|
## Vision
|
|
|
|
Build a transparent, deterministic rod-string and wellbore mechanics platform that is field-usable and research-grade.
|
|
|
|
- Physically explainable pumping-system simulations, not black-box outputs.
|
|
- Dynamometer cards as the primary interpretation surface.
|
|
- Inspectability of imported case data and solver assumptions.
|
|
- Multi-model validation (FDM vs FEA) with clear comparison metadata.
|
|
|
|
## Prerequisites
|
|
|
|
- **Local:** `gcc`, `make`, Node 20+, `npm`
|
|
- **Docker:** Docker Engine + Compose plugin
|
|
|
|
## Run locally
|
|
|
|
### Build and run C solver (stdin JSON)
|
|
|
|
The API spawns `solver-c/solver_main` and pipes **one JSON object** on stdin (`schemaVersion: 2`). Legacy 9-argument CLI is **removed**.
|
|
|
|
```bash
|
|
gcc -std=c99 -I./solver-c/include \
|
|
./solver-c/src/solver_common.c \
|
|
./solver-c/src/json_stdin.c \
|
|
./solver-c/src/trajectory.c \
|
|
./solver-c/src/solver_diagnostic.c \
|
|
./solver-c/src/solver.c \
|
|
./solver-c/src/solver_fea.c \
|
|
./solver-c/src/solver_fourier.c \
|
|
./solver-c/src/main.c -lm -o ./solver-c/solver_main
|
|
|
|
gcc -std=c99 -I./solver-c/include \
|
|
./solver-c/src/solver_common.c \
|
|
./solver-c/src/json_stdin.c \
|
|
./solver-c/src/trajectory.c \
|
|
./solver-c/src/solver_diagnostic.c \
|
|
./solver-c/src/solver.c \
|
|
./solver-c/src/solver_fea.c \
|
|
./solver-c/src/solver_fourier.c \
|
|
./solver-c/src/main_fea.c -lm -o ./solver-c/solver_fea_main
|
|
|
|
./solver-c/test_solver
|
|
```
|
|
|
|
### API + GUI
|
|
|
|
```bash
|
|
cd solver-api && npm install && npm run dev
|
|
cd gui-ts && npm install && npm run dev
|
|
```
|
|
|
|
- API: `http://localhost:4400/health`
|
|
- GUI: `http://localhost:5173`
|
|
|
|
## Run with Docker
|
|
|
|
```bash
|
|
make run # or: docker compose up --build
|
|
make smoke # requires API on 4400
|
|
make down
|
|
```
|
|
|
|
## Validation
|
|
|
|
```bash
|
|
make test # solver-api vitest + gui-ts tests + solver-c test_solver
|
|
./solver-c/test_solver
|
|
```
|
|
|
|
Golden hash: `solver-api` tests assert `/solve/default` body matches `data/golden/default.solve.sha256` (after normalizing `generatedAt`).
|
|
|
|
## API examples
|
|
|
|
### Predictive (default base case)
|
|
|
|
```bash
|
|
curl -sS "http://localhost:4400/solve/default?solverModel=both" | jq '.schemaVersion, .runMetadata, .comparison | keys'
|
|
```
|
|
|
|
### Predictive (POST XML)
|
|
|
|
```bash
|
|
curl -sS -X POST http://localhost:4400/solve \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"xml\": $(jq -Rs . < data/cases/base-case.xml), \"solverModel\": \"fdm\"}" | jq '.solver.pointCount, .schemaVersion'
|
|
```
|
|
|
|
### Extended physics outputs (profiles/diagnostics/fourier)
|
|
|
|
```bash
|
|
curl -sS -X POST http://localhost:4400/solve \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"xml\": $(jq -Rs . < data/cases/base-case.xml), \"solverModel\": \"both\", \"options\": {\"enableProfiles\": true, \"enableDiagnosticsDetail\": true, \"enableFourierBaseline\": true, \"fourierHarmonics\": 10}}" \
|
|
| jq '.solver.profiles.nodeCount, .solver.diagnostics.valveStates[0], .comparison.fourier.harmonics'
|
|
```
|
|
|
|
### Diagnostic (measured surface card)
|
|
|
|
Build `surfaceCard` from a predictive run or field data:
|
|
|
|
```bash
|
|
CARD=$(curl -sS "http://localhost:4400/solve/default?solverModel=fdm")
|
|
# Then POST xml + workflow + surfaceCard (see solver-api/tests/api.test.js)
|
|
```
|
|
|
|
### Surface card QA only
|
|
|
|
```bash
|
|
curl -sS -X POST http://localhost:4400/solve/validate-card \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"surfaceCard":{"position":[0,1,2],"load":[10,11,12]}}' | jq .
|
|
```
|
|
|
|
### Parse XML only (no solve)
|
|
|
|
```bash
|
|
curl -sS -X POST http://localhost:4400/case/parse \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"xml\": $(jq -Rs . < data/cases/base-case.xml)}" | jq '.schemaVersion, .model.wellName, (.unsupportedFields | length)'
|
|
```
|
|
|
|
Returns `{ model, rawFields, unsupportedFields, warnings, schemaVersion: 2 }` — same shape as `GET /case/default`, but for an uploaded XML string. Used by the GUI to hydrate its case editor from an import.
|
|
|
|
## GUI tabbed case editor
|
|
|
|
`gui-ts` renders a tabbed UI backed by a single `CaseState` that round-trips to/from the XML document. On first load it pulls `GET /case/default` and populates every tab; editing any field mutates `CaseState`, which is serialized back into `<INPRoot><Case>…</Case></INPRoot>` on solve or export. Untouched XML fields (fatigue, IPR blocks, pumping-unit catalog keys, etc.) are preserved verbatim in the output.
|
|
|
|
| Tab | Contents |
|
|
|-----|----------|
|
|
| Well | Well name, company, units selection, pump depth, tubing anchor / size |
|
|
| Trajectory | Editable MD / Inc / Az survey table with vertical + deviated presets |
|
|
| Kinematics | Pumping speed (SPM), speed option, unit ID, upstroke/downstroke percentages |
|
|
| Rod String | Taper table (diameter, length, modulus, rod type) with base-case preset |
|
|
| Pump | Plunger diameter, friction, intake pressure, fillage option + percent |
|
|
| Fluid | Water cut, water SG, oil API, tubing gradient |
|
|
| Solver | `solverModel` (fdm/fea/both), workflow selector, damping + friction knobs, engineering checks gate, **Run Solver** |
|
|
| Results | KPI banner, uPlot dynacard (polished + downhole, with FEA overlay when applicable), FDM↔FEA comparison, warnings, unsupported-field list, 3D wellbore/rod/pump view with DLS or side-load contour, trajectory analytics table, pump diagnostics, export tools |
|
|
| Advanced / XML | File upload + paste box (POST `/case/parse`), export current state as XML, raw-field inspector |
|
|
|
|
### Built-in engineering checks
|
|
|
|
- **Pump depth vs total rod length:** solver run is blocked if the absolute mismatch exceeds **15 m**.
|
|
- **Trajectory integrity:** requires at least 2 stations and strictly increasing measured depth.
|
|
- **DLS warning threshold:** if max dogleg severity exceeds **15 deg/100**, the UI surfaces a warning.
|
|
|
|
These are fixed guardrails (not user configurable) to keep behavior deterministic and consistent across sessions.
|
|
|
|
### 3D wellbore visualization
|
|
|
|
The Results tab includes a 3D projected wellbore panel:
|
|
|
|
- Tubing trajectory polyline colored by DLS contour (green/yellow/red).
|
|
- **Bad sections** highlighted in red for DLS >= **15 deg/100**.
|
|
- Rod string overlay drawn from surface to rod total length with depth color gradient.
|
|
- Pump marker placed along trajectory at `PumpDepth`.
|
|
- Interactive controls: drag to rotate, `Shift+drag` to pan, mouse wheel / buttons to zoom, projection toggle (perspective/orthographic), and reset view.
|
|
- Overlay modes:
|
|
- `DLS`: uses fixed bad-section threshold `15 deg/100`
|
|
- `Side-load risk`: colors by normalized side-load profile returned from solver outputs (`options.enableProfiles=true`)
|
|
|
|
### Trajectory analytics + cross-highlight
|
|
|
|
- Results includes a per-segment trajectory table (`MD start/end`, `ΔMD`, `DLS`, severity).
|
|
- Clicking a segment row highlights the corresponding 3D trajectory segment.
|
|
- Clicking a segment in 3D highlights the corresponding table row.
|
|
- Filter toggle supports "bad sections only".
|
|
- Keyboard accessibility: segment rows are focusable and selectable with `Enter` / `Space`.
|
|
|
|
### Pump placement diagnostics
|
|
|
|
Results tab now reports:
|
|
- nearest survey station to pump depth,
|
|
- pump-to-station `ΔMD`,
|
|
- survey-end to pump `ΔMD`,
|
|
- rod-total to pump `Δ`,
|
|
- tubing-anchor to pump `Δ`,
|
|
with quick navigation buttons back to Well / Trajectory / Rod tabs for correction.
|
|
|
|
### Visualization artifact export
|
|
|
|
Results tab export buttons:
|
|
- 3D wellbore **SVG**
|
|
- 3D wellbore **PNG**
|
|
- run/check summary **JSON**
|
|
|
|
These are generated client-side from the rendered SVG and current run/check state.
|
|
|
|
### Diagnostic workflow (GUI wired)
|
|
|
|
- Kinematics tab accepts measured surface card points as `position,load` rows.
|
|
- `Validate Surface Card` calls `POST /solve/validate-card`.
|
|
- Solver tab `workflow=diagnostic` now sends `surfaceCard` to `POST /solve`.
|
|
- Solve calls include `options.enableProfiles=true` so side-load overlays can be rendered.
|
|
|
|
## Solver modes
|
|
|
|
| `solverModel` | Behavior |
|
|
|----------------|----------|
|
|
| `fdm` | Finite-difference damped wave + variable rod + trajectory friction |
|
|
| `fea` | 1D bar FEM + Newmark + Rayleigh damping |
|
|
| `both` | Runs FDM + FEA; returns `solvers` and extended `comparison` |
|
|
|
|
| `workflow` | Behavior |
|
|
|-------------|----------|
|
|
| `predictive` | Harmonic surface motion (unless overridden later) |
|
|
| `diagnostic` | Surface card BC; FDM in C; FEA uses bisection on pump load to match measured top load |
|
|
|
|
## Optional CI image
|
|
|
|
```bash
|
|
docker build -t rods-ci .
|
|
docker run --rm rods-ci
|
|
```
|
|
|
|
## Where to read next
|
|
|
|
1. [AGENTS.md](AGENTS.md)
|
|
2. [Agents/MATH_SPEC.md](Agents/MATH_SPEC.md)
|
|
3. [Agents/COMPUTE_PLAN.md](Agents/COMPUTE_PLAN.md)
|
|
4. [docs/engineering/units.md](docs/engineering/units.md)
|
|
5. [docs/engineering/validation.md](docs/engineering/validation.md)
|