Skip to content

Commit 72605aa

Browse files
Add CLAUDE.md (#337)
1 parent cd03383 commit 72605aa

2 files changed

Lines changed: 226 additions & 1 deletion

File tree

.pre-commit-config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ repos:
3939
- id: prettier
4040
types_or: [yaml, markdown, html, css, scss, javascript, json]
4141
args: [--prose-wrap=always]
42+
exclude: ^CLAUDE\.md$
4243

4344
- repo: https://github.com/astral-sh/ruff-pre-commit
4445
rev: "v0.4.1"
@@ -74,7 +75,7 @@ repos:
7475
name: Disallow improper capitalization
7576
language: pygrep
7677
entry: PyBind|Numpy|Cmake|CCache|Github|PyTest
77-
exclude: .pre-commit-config.yaml
78+
exclude: (?x)(^\.pre-commit-config\.yaml$|^CLAUDE\.md$)
7879

7980
- repo: https://github.com/python-jsonschema/check-jsonschema
8081
rev: "0.28.2"

CLAUDE.md

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with
4+
code in this repository.
5+
6+
## Project Overview
7+
8+
`openlifu` is the core Python library for Openwater's Low Intensity Focused
9+
Ultrasound (LIFU) platform. It provides beamforming, k-Wave acoustic simulation,
10+
treatment planning, a file-based database, and hardware I/O. Licensed under MIT.
11+
12+
The primary downstream consumer is **SlicerOpenLIFU** (`../SlicerOpenLIFU`), a
13+
3D Slicer extension that wraps `openlifu` objects with a GUI, VTK visualization,
14+
and MRML persistence.
15+
16+
Python 3.10-3.12 on Windows or Linux.
17+
18+
## Build and Development Commands
19+
20+
```bash
21+
# Install (editable, with test deps)
22+
pip install -e '.[test]'
23+
24+
# Install (editable, with dev deps)
25+
pip install -e '.[dev]'
26+
27+
# Run all tests
28+
pytest
29+
30+
# Run a single test file
31+
pytest tests/test_database.py
32+
33+
# Run a single test function
34+
pytest tests/test_database.py::test_function_name -v
35+
36+
# Run tests with coverage
37+
pytest -ra --cov --cov-report=term --durations=20
38+
39+
# Lint (runs pre-commit hooks)
40+
pipx run nox -s lint
41+
# or if nox is installed:
42+
nox -s lint
43+
44+
# Run ruff directly
45+
ruff check src/
46+
47+
# Run pylint
48+
nox -s pylint
49+
50+
# Build docs
51+
nox -s docs
52+
```
53+
54+
## Linting and Code Style
55+
56+
- **Ruff** is the primary linter, configured in `pyproject.toml` with many rule
57+
sets enabled (bugbear, isort, pylint, etc.).
58+
- **Every file must start with `from __future__ import annotations`** — enforced
59+
by isort via `isort.required-imports` in `pyproject.toml`.
60+
- **No auto-formatter** is currently enabled (ruff-format is commented out in
61+
`.pre-commit-config.yaml`).
62+
- **Pre-commit hooks** include: ruff (with `--fix`), codespell, shellcheck,
63+
prettier (YAML/MD/JSON), blacken-docs, and a custom check disallowing
64+
`PyBind|Numpy|Cmake|CCache|Github|PyTest` capitalization.
65+
- **PyLint** runs in CI via nox. MyPy is disabled.
66+
- Warnings are treated as errors in pytest, with specific exceptions listed in
67+
`pyproject.toml`.
68+
69+
## CI
70+
71+
CI runs on push to main and on PRs (`.github/workflows/ci.yml`):
72+
73+
1. **Commit message check** (PRs only): every commit must reference a GitHub
74+
issue (`#123` or full URL). Exceptions: Bump, Merge, Revert, fixup!, squash!,
75+
amend! commits.
76+
2. **Pre-commit + PyLint**: linting on ubuntu.
77+
3. **Tests**: matrix of Python {3.10, 3.12} x {ubuntu, windows, macos} with
78+
coverage uploaded to Codecov.
79+
80+
## Commit Guidelines
81+
82+
Every commit must reference a relevant GitHub issue number in the title or body
83+
(e.g. `Fix target placement crash (#42)` or `Fixes #42` in the body). CI
84+
enforces this on PRs.
85+
86+
## Architecture
87+
88+
### Subpackages
89+
90+
| Package | Purpose |
91+
| -------- | ----------------------------------------------------------------------------------------------- |
92+
| `plan/` | `Protocol` and `Solution` — treatment planning, beamforming orchestration, solution analysis |
93+
| `bf/` | Beamforming primitives: `Pulse`, `Sequence`, `FocalPattern`, `DelayMethod`, `ApodizationMethod` |
94+
| `sim/` | k-Wave acoustic simulation integration (`SimSetup`, `run_simulation`) |
95+
| `db/` | File-based JSON database (`Database`, `User`, `Subject`, `Session`, `Run`) |
96+
| `xdc/` | Transducer hardware definitions (`Transducer`, `Element`, `TransducerArray`) |
97+
| `seg/` | Tissue segmentation and material properties (`Material`, `SegmentationMethod`) |
98+
| `geo.py` | `Point` class — 3D coordinates with metadata and VTK visualization |
99+
| `io/` | Hardware communication (`LIFUInterface`) — USB, serial, voltage safety |
100+
| `nav/` | Photogrammetry (`Photoscan`), Meshroom pipeline integration, MODNet portrait matting |
101+
| `virtual_fit.py` | Virtual fit algorithm — transducer positioning optimization (top-level module, not a subpackage) |
102+
| `cloud/` | REST API client for cloud-based session sync, WebSocket support |
103+
| `util/` | Shared infrastructure: `DictMixin`, `PYFUSEncoder`, unit conversion, volume conversion |
104+
105+
### Core Domain Model
106+
107+
```
108+
Protocol (treatment plan template)
109+
├── Pulse, Sequence, FocalPattern
110+
├── DelayMethod, ApodizationMethod
111+
├── SegmentationMethod
112+
└── SimSetup
113+
114+
▼ Protocol.calc_solution(target, transducer, volume)
115+
Solution (computed beam parameters: delays[], apodizations[], foci[])
116+
├── simulate() → xarray.Dataset (pressure fields)
117+
├── analyze() → SolutionAnalysis (pressure/safety metrics)
118+
└── scale() → adjust voltage to target pressure
119+
120+
Session
121+
├── Subject, Protocol, Transducer, Volume
122+
├── targets[] (Point), markers[]
123+
└── virtual_fit_results, transducer_tracking_results
124+
```
125+
126+
### Serialization Patterns
127+
128+
Three patterns are used consistently:
129+
130+
1. **`DictMixin`** (`util/dict_conversion.py`): automatic
131+
`to_dict()`/`from_dict()` from dataclass fields. Used by simpler classes
132+
(Sequence, Pulse, SimSetup, Material, VirtualFitOptions, Subject).
133+
134+
2. **Manual `to_dict`/`from_dict`/`to_json`/`from_json`/`to_file`/`from_file`**:
135+
used by Protocol, Solution, Point, User, Run.
136+
137+
3. **Polymorphic factory with class name lookup**: abstract base classes store
138+
`{'class': 'ClassName', ...}` in dicts and reconstruct via module
139+
introspection. Used by DelayMethod, ApodizationMethod, FocalPattern,
140+
SegmentationMethod.
141+
142+
All JSON encoding uses `PYFUSEncoder` (`util/json.py`) which handles numpy
143+
types, datetime, and domain objects.
144+
145+
### Database File Layout
146+
147+
Each top-level resource has an index JSON listing its members (`users.json`,
148+
`protocols.json`, `subjects.json`, `transducers.json`); nested collections have
149+
their own index files alongside.
150+
151+
```
152+
{db_root}/
153+
users/users.json
154+
users/{user_id}/... → User record + password hash
155+
protocols/protocols.json
156+
protocols/{protocol_id}/... → Protocol JSON
157+
subjects/subjects.json
158+
subjects/{subject_id}/{subject_id}.json → Subject record
159+
subjects/{subject_id}/volumes/volumes.json
160+
subjects/{subject_id}/volumes/{volume_id}/...
161+
subjects/{subject_id}/sessions/sessions.json
162+
subjects/{subject_id}/sessions/{session_id}/{session_id}.json
163+
subjects/{subject_id}/sessions/{session_id}/runs/runs.json
164+
subjects/{subject_id}/sessions/{session_id}/solutions/solutions.json
165+
subjects/{subject_id}/sessions/{session_id}/solutions/{solution_id}/... → Solution JSON + .nc
166+
subjects/{subject_id}/sessions/{session_id}/photoscans/photoscans.json
167+
subjects/{subject_id}/sessions/{session_id}/photocollections/photocollections.json
168+
transducers/transducers.json
169+
transducers/{transducer_id}/{transducer_id}.json → Transducer JSON
170+
transducers/{transducer_id}/{transducer_id}_gridweights_{hash}.h5 → Precomputed grid weights
171+
```
172+
173+
### Parameter Constraints
174+
175+
`ParameterConstraint` provides validation with operators (`<`, `<=`, `>`, `>=`,
176+
`within`, `inside`, `outside`) and warning/error thresholds. `TargetConstraints`
177+
validates spatial bounds per dimension. Both used during
178+
`Protocol.calc_solution()` and `Solution.analyze()`.
179+
180+
### Simulation Pipeline
181+
182+
`Protocol.calc_solution()` flow:
183+
184+
1. Validate target against `TargetConstraints`
185+
2. Create simulation params from volume + `SegmentationMethod`
186+
3. For each focal point: compute delays (`DelayMethod`) and apodizations
187+
(`ApodizationMethod`)
188+
4. Create `Solution` with stacked delay/apodization arrays
189+
5. `Solution.simulate()` → k-Wave via `run_simulation()` → xarray Dataset
190+
6. `Solution.scale()` → adjust voltage for target pressure
191+
7. `Solution.analyze()``SolutionAnalysis` (PNP, ISPPA, ISPTA, MI, TIC,
192+
beamwidths, temperature)
193+
194+
## Testing
195+
196+
- Tests use **pytest** (not Slicer's test framework — that's SlicerOpenLIFU).
197+
- No shared `conftest.py` — fixtures are local to each test file.
198+
- `tests/helpers.py` provides `dataclasses_are_equal()` for deep equality of
199+
nested dataclass/numpy structures.
200+
- Test data lives in `tests/resources/` (includes `example_db/` and a DICOM
201+
file).
202+
- The full sample database is published as its own repo (see "Sample Data"
203+
below); it is not pulled in by the test suite.
204+
205+
## Sample Data
206+
207+
The official sample database lives in
208+
[`openlifu-sample-database`](https://github.com/OpenwaterHealth/openlifu-sample-database)
209+
and is tracked with Git LFS. Tags on that repo (e.g. `openlifu-v0.20.0`) pin
210+
sample-data versions to specific `openlifu` releases, and downstream releases
211+
(SlicerOpenLIFU, openlifu-app) link to the README section below for the
212+
compatible version.
213+
214+
```bash
215+
git clone --depth 1 --branch openlifu-v0.20.0 https://github.com/OpenwaterHealth/openlifu-sample-database.git
216+
cd openlifu-sample-database
217+
git lfs pull
218+
```
219+
220+
The legacy DVC flow (`db_dvc/`, `db_dvc.dvc`, `dvc[gdrive]` in the `dev` extra,
221+
Google Drive remote with `gdrive_client_secret`) is still present in the repo
222+
but is not the path users or downstream consumers should be pointed to. Direct
223+
customers and downstream projects to the README section "Getting Sample Data"
224+
instead.

0 commit comments

Comments
 (0)