Skip to content

Commit 661833d

Browse files
committed
Add CLAUDE.md: comprehensive AI assistant guide for the venting codebase
Covers project overview, directory layout, development setup, CLI usage, architecture/data-flow, key dataclasses, flow models, thermodynamic modes, physics conventions, testing conventions, code style, CI/CD, known limitations, and a quick-reference for adding new features. https://claude.ai/code/session_012Grghj8yX4bqC5MVkHqyfj
1 parent 301ca09 commit 661833d

1 file changed

Lines changed: 322 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
# CLAUDE.md — Venting Codebase Guide for AI Assistants
2+
3+
This file provides context for AI assistants (Claude, Copilot, etc.) working in the
4+
`venting` repository. Read it before modifying any code.
5+
6+
---
7+
8+
## Project Overview
9+
10+
**Venting v10.0.0** is a 0D/network depressurization solver for aerospace and
11+
industrial pressure-relief analysis. It models rigid gas volumes (nodes) connected
12+
by orifices or channels (edges) and integrates the resulting stiff ODE system using
13+
SciPy's Radau solver.
14+
15+
- **Not CFD.** No spatial fields, no shocks, no acoustics — purely lumped-parameter.
16+
- **Primary output:** maximum `|ΔP|` across each edge and whether flow is choked.
17+
- **Python ≥ 3.10**, MIT license.
18+
19+
---
20+
21+
## Repository Layout
22+
23+
```
24+
venting/
25+
├── src/venting/ # Main package (src-layout, installed as `venting`)
26+
│ ├── __init__.py # Version: 10.0.0
27+
│ ├── __main__.py # `python -m venting` entry point
28+
│ ├── cli.py # Argparse CLI (subcommands: gate, sweep, sweep2d, …)
29+
│ ├── constants.py # Physical constants (γ, R, π_c, safety thresholds)
30+
│ ├── cases.py # Frozen dataclasses: CaseConfig, NetworkConfig, SolveResult
31+
│ ├── geometry.py # Unit converters (mm↔m, circle area)
32+
│ ├── profiles.py # External pressure profiles (linear/step/barometric/table)
33+
│ ├── graph.py # Network topology builder: GasNode, Orifice, ShortTube, SlotChannel
34+
│ ├── flow.py # Mass-flow functions: orifice, short_tube, slot, Fanno, Sutherland
35+
│ ├── solver.py # ODE RHS, solve_ivp (Radau), sparsity, events, streaming
36+
│ ├── diagnostics.py # Peak detection, τ_exit, pressure regime classification
37+
│ ├── validity.py # Physical validity flags (acoustic timescale, Re, Mach, thermo)
38+
│ ├── gates.py # 5 analytical gate tests (single-node, two-node, conservation)
39+
│ ├── io.py # Artifact export: run.json, summary.csv, .npz, meta.json
40+
│ ├── run.py # High-level case execution pipeline
41+
│ ├── compare.py # Run-comparison and loading utilities
42+
│ ├── plotting.py # Matplotlib ΔP-vs-time visualization (Agg backend)
43+
│ ├── montecarlo.py # Latin-hypercube parametric sampling
44+
│ ├── presets.py # Default panel geometry (volumes, wall areas)
45+
│ ├── thermo.py # NASA-7 polynomial fits: cp(T), cv(T), γ(T), h(T)
46+
│ ├── state_layout.py # ODE state-vector slicing (m, T, T_wall indices)
47+
│ └── gui/ # Optional PySide6/pyqtgraph desktop interface
48+
│ ├── main.py
49+
│ ├── app.py
50+
│ ├── config.py
51+
│ └── state_layout.py
52+
├── tests/ # pytest test suite (~900 lines, 15 files)
53+
├── docs/ # Markdown physics docs and verification criteria
54+
├── archive/ # Legacy monolithic script (reference only, not imported)
55+
├── .github/workflows/ # CI: Python 3.10–3.12 matrix, ruff, black, pytest
56+
├── pyproject.toml # Project metadata, build config, tool settings
57+
├── requirements.txt # Runtime deps (numpy, scipy, matplotlib)
58+
├── requirements-dev.txt # Dev deps (-e .[dev])
59+
├── .pre-commit-config.yaml
60+
├── README.md # Bilingual (Russian + English) physics and CLI reference
61+
└── CONTRIBUTING.md
62+
```
63+
64+
---
65+
66+
## Development Setup
67+
68+
```bash
69+
# Install in editable mode with dev dependencies
70+
pip install -e ".[dev]"
71+
72+
# Install pre-commit hooks (ruff + black auto-fix on every commit)
73+
pre-commit install
74+
```
75+
76+
### Optional GUI
77+
78+
```bash
79+
pip install -e ".[gui]" # adds PySide6, pyqtgraph
80+
python -m venting gui
81+
```
82+
83+
---
84+
85+
## Running Tests
86+
87+
```bash
88+
# Fast (CI-equivalent)
89+
pytest -q
90+
91+
# With coverage
92+
pytest -q --cov=venting --cov-report=term-missing
93+
94+
# Single test file
95+
pytest tests/test_gates.py -v
96+
```
97+
98+
All tests are deterministic. Gate tests validate against hardcoded analytic solutions
99+
with tight tolerances (`< 0.5%` for physics, `< 0.1%` for mass conservation).
100+
101+
---
102+
103+
## Linting and Formatting
104+
105+
```bash
106+
ruff check . # Lint (F, E, I, B, UP rules; E501 ignored)
107+
ruff check . --fix # Auto-fix safe issues
108+
black . # Format (line-length 88)
109+
black --check . # Format check only
110+
```
111+
112+
Pre-commit hooks run ruff and black automatically on `git commit`.
113+
114+
---
115+
116+
## CLI Commands
117+
118+
```bash
119+
python -m venting gate # Run all 5 analytical gate tests
120+
python -m venting gate --single # Single-node validation only
121+
python -m venting gate --two # Two-node validation only
122+
123+
python -m venting sweep # 1D parameter sweep (d_int, d_exit, Cd)
124+
python -m venting sweep2d # 2D grid sweep
125+
python -m venting thermal # Multi-h thermal sensitivity
126+
python -m venting montecarlo # Latin-hypercube parametric sampling
127+
128+
python -m venting compare dir1 dir2 # Compare two run result directories
129+
130+
python -m venting gui # Launch PySide6 desktop interface
131+
```
132+
133+
---
134+
135+
## Architecture and Data Flow
136+
137+
```
138+
NetworkConfig / CaseConfig
139+
140+
141+
graph.py ──► builds list of GasNode + edge objects
142+
143+
144+
solver.py ──► constructs ODE RHS using flow.py functions
145+
│ applies sparsity pattern for Radau Jacobian
146+
│ integrates with scipy.integrate.solve_ivp
147+
148+
SolveResult (time array + state array)
149+
150+
├──► diagnostics.py ──► peak ΔP, τ_exit, regime (CHOKED/subsonic)
151+
├──► validity.py ──► physical flag checks
152+
└──► io.py ──► run.json, summary.csv, .npz, meta.json
153+
```
154+
155+
### ODE State Vector Layout (`state_layout.py`)
156+
157+
For a network with `N` nodes:
158+
159+
| Slice | Variables |
160+
|-------|-----------|
161+
| `[0:N]` | mass `m[i]` (kg) for each node |
162+
| `[N:2N]` | temperature `T[i]` (K) — only if `mode != "isothermal"` |
163+
| `[2N:3N]` | wall temperature `T_wall[i]` (K) — only if `lumped_wall=True` |
164+
165+
---
166+
167+
## Key Dataclasses (`cases.py`)
168+
169+
All config objects are **frozen dataclasses** (immutable after construction).
170+
171+
- **`CaseConfig`** — thermodynamic mode (`"isothermal"` / `"intermediate"` / `"variable"`),
172+
wall model settings, external model selection.
173+
- **`NetworkConfig`** — node volumes/temperatures, edge geometry (diameters, Cd, lengths),
174+
network topology (n_cells, n_chains, vestibule flag).
175+
- **`SolveResult`**`t`, `y` arrays from solve_ivp, plus metadata.
176+
177+
---
178+
179+
## Flow Models (`flow.py`)
180+
181+
| Model | Function | Notes |
182+
|-------|----------|-------|
183+
| Sharp-edged orifice | `mdot_orifice(...)` | Cd-based, choked/subsonic |
184+
| Short-tube | `mdot_short_tube(...)` | Darcy friction + K_in/K_out minor losses; uses effective Cd, not Fanno |
185+
| Slot channel | `mdot_slot(...)` | Viscous laminar (Poiseuille) |
186+
| Fanno flow | `mdot_fanno(...)` | Friction-limited choked flow (available but not default in v10) |
187+
188+
**Sentinel values** (defined in `constants.py`):
189+
- `EXT_NODE = -1` — marks external-atmosphere boundary nodes
190+
- `M_SAFE`, `T_SAFE` — minimum safe mass/temperature to avoid division by zero
191+
- `P_STOP` — solver early-stop pressure threshold
192+
193+
---
194+
195+
## Thermodynamic Modes
196+
197+
| Mode | T evolution | Notes |
198+
|------|------------|-------|
199+
| `"isothermal"` | `T = T₀` (fixed) | Fast; valid when walls are highly conductive |
200+
| `"intermediate"` | Solves `dT/dt` with wall heat transfer | Default recommendation |
201+
| `"variable"` | Same as intermediate + NASA-7 `cp(T)`, `cv(T)`, `γ(T)` | Most accurate |
202+
203+
Use `thermo.py` functions when `mode == "variable"`. The NASA-7 fits are valid for
204+
air in the range ~200–2000 K.
205+
206+
---
207+
208+
## External Pressure Profiles (`profiles.py`)
209+
210+
Profiles define `P_ext(t)` for the environment node:
211+
212+
| Profile | Description |
213+
|---------|-------------|
214+
| `"linear"` | Linearly drops from `P0` to `P_final` over `t_final` |
215+
| `"step"` | Instantaneous step at `t_step` |
216+
| `"barometric"` | Exponential decay (e.g., rocket ascent) |
217+
| `"table"` | Interpolated from user-supplied `(t, P)` data |
218+
219+
---
220+
221+
## Output Artifacts (`io.py`)
222+
223+
| File | Contents |
224+
|------|----------|
225+
| `run.json` | Reproducibility metadata: git commit, Python version, all input parameters |
226+
| `summary.csv` | Per-edge metrics: max ΔP, peak time, flow regime, peak type |
227+
| `*.npz` | Compressed time series: `t, m, T, P, P_ext, τ_exit` |
228+
| `*_meta.json` | Peak diagnostics and validity flags |
229+
| `*_validity.json` | Physical validity summary (Re, Mach, acoustic checks) |
230+
231+
---
232+
233+
## Physics Conventions
234+
235+
- **Ideal gas EOS:** `P = m R T / V`
236+
- **Mass balance:** `dm/dt = Σ ṁ_in − Σ ṁ_out`
237+
- **Energy balance (non-isothermal):** `m cv dT/dt = Σ ṁ_in (cp T_in − cv T) − Σ ṁ_out (R T) + h A ΔT`
238+
- **Choking condition:** `P_up / P_down ≥ π_c = ((γ+1)/2)^(γ/(γ−1))`
239+
- **Default constants:** `γ = 1.4`, `R = 287.05 J/(kg·K)`
240+
- **No state clipping:** The solver avoids aggressive clipping; safety guards apply
241+
only to denominators (`M_SAFE`, `T_SAFE`).
242+
243+
---
244+
245+
## Validity Checks (`validity.py`)
246+
247+
After each solve, `validity.py` produces flags:
248+
249+
- **Acoustic timescale:** Is the ODE timestep >> acoustic propagation time? (0D
250+
assumption must hold.)
251+
- **Thermodynamic range:** Are temperatures within NASA-7 polynomial validity?
252+
- **Short-tube Re/Mach:** Is viscous laminar assumption self-consistent?
253+
- **Friction factor:** Is Darcy friction in the expected regime?
254+
255+
Always inspect validity flags before trusting results.
256+
257+
---
258+
259+
## Testing Conventions
260+
261+
- **Gate tests (`test_gates.py`):** Compare solver to hardcoded analytic solutions.
262+
Tolerances: `< 0.5%` for pressures, `< 0.1%` for mass conservation.
263+
- **Validity checks are masked:** Only high-pressure region (`P > 0.01 P0`) is
264+
validated to avoid noise near equilibrium.
265+
- **No flaky tests:** All tests use deterministic inputs with fixed random seeds
266+
where sampling is involved.
267+
- **GUI tests skip gracefully** if PySide6 is not installed.
268+
269+
---
270+
271+
## Code Style Rules
272+
273+
- **Formatter:** Black (line-length 88). Run before committing.
274+
- **Linter:** Ruff with rules `F, E, I, B, UP` (no `E501`).
275+
- **Type hints:** Used throughout; mypy is available but not enforced in CI.
276+
- **Dataclasses:** Prefer `@dataclass(frozen=True)` for config objects.
277+
- **Pure functions:** Flow model functions in `flow.py` are stateless.
278+
- **No magic numbers:** Physical constants live in `constants.py`.
279+
- **Archive is read-only:** `archive/venting_v84.py` is reference only; do not
280+
import from it in production code or tests.
281+
282+
---
283+
284+
## CI/CD
285+
286+
GitHub Actions (`.github/workflows/ci.yml`) runs on every push and pull request:
287+
288+
1. Python matrix: **3.10, 3.11, 3.12** on `ubuntu-latest`
289+
2. `pip check` — dependency consistency
290+
3. `ruff check .` — linting
291+
4. `black --check .` — formatting
292+
5. `pytest -q --cov=venting` — tests with coverage
293+
294+
All steps must pass before merging.
295+
296+
---
297+
298+
## Known Limitations
299+
300+
- **Not CFD:** No spatial velocity or temperature gradients, no acoustic wave
301+
propagation, no shock capturing.
302+
- **C_d is the primary uncertainty:** Always run a Cd sweep to understand
303+
sensitivity before drawing conclusions.
304+
- **Short-tube model:** Lossy-nozzle via Cd_eff (v10 default). Fanno
305+
friction-choking is implemented but not the default.
306+
- **Streaming vs. batch solve:** Results agree within integrator tolerances but
307+
may differ at the last decimal place due to chunking.
308+
- **GUI packaging:** Bundling as a standalone executable is a known TODO.
309+
310+
---
311+
312+
## Quick Reference: Adding a New Feature
313+
314+
1. **New flow model** → add a function to `flow.py`; wire into `graph.py` edge
315+
dispatch; update `state_layout.py` if state vector changes.
316+
2. **New external profile** → add a class/function to `profiles.py`; register it
317+
in the CLI (`cli.py`) and in `cases.py`.
318+
3. **New CLI subcommand** → add a `add_parser` block in `cli.py` and a handler
319+
function; keep handler thin, delegate to `run.py` or domain modules.
320+
4. **New test** → add to `tests/`; gate tests go in `test_gates.py` if they have
321+
an analytic solution, otherwise create a regression test file.
322+
5. **Always run:** `ruff check . --fix && black . && pytest -q` before committing.

0 commit comments

Comments
 (0)