monai-physio 2026.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- monai_physio-2026.9.0/AGENTS.md +287 -0
- monai_physio-2026.9.0/CLAUDE.md +222 -0
- monai_physio-2026.9.0/LICENSE +201 -0
- monai_physio-2026.9.0/MANIFEST.in +35 -0
- monai_physio-2026.9.0/PKG-INFO +250 -0
- monai_physio-2026.9.0/README.md +150 -0
- monai_physio-2026.9.0/pyproject.toml +620 -0
- monai_physio-2026.9.0/setup.cfg +4 -0
- monai_physio-2026.9.0/src/monai_physio/__init__.py +202 -0
- monai_physio-2026.9.0/src/monai_physio/anatomy_taxonomy.py +164 -0
- monai_physio-2026.9.0/src/monai_physio/cli/__init__.py +15 -0
- monai_physio-2026.9.0/src/monai_physio/cli/_method_factories.py +91 -0
- monai_physio-2026.9.0/src/monai_physio/cli/convert_image_4d_to_3d.py +109 -0
- monai_physio-2026.9.0/src/monai_physio/cli/convert_image_to_usd.py +192 -0
- monai_physio-2026.9.0/src/monai_physio/cli/convert_image_to_vtk.py +236 -0
- monai_physio-2026.9.0/src/monai_physio/cli/convert_vtk_to_usd.py +249 -0
- monai_physio-2026.9.0/src/monai_physio/cli/create_statistical_model.py +184 -0
- monai_physio-2026.9.0/src/monai_physio/cli/download_data.py +89 -0
- monai_physio-2026.9.0/src/monai_physio/cli/fit_statistical_model_to_patient.py +342 -0
- monai_physio-2026.9.0/src/monai_physio/cli/infer_physicsnemo.py +153 -0
- monai_physio-2026.9.0/src/monai_physio/cli/reconstruct_highres_4d_ct.py +410 -0
- monai_physio-2026.9.0/src/monai_physio/cli/train_physicsnemo.py +138 -0
- monai_physio-2026.9.0/src/monai_physio/cli/visualize_pca_modes.py +282 -0
- monai_physio-2026.9.0/src/monai_physio/convert_image_4d_to_3d.py +301 -0
- monai_physio-2026.9.0/src/monai_physio/convert_vtk_to_usd.py +1071 -0
- monai_physio-2026.9.0/src/monai_physio/download_data.py +495 -0
- monai_physio-2026.9.0/src/monai_physio/evaluate_movement_base.py +151 -0
- monai_physio-2026.9.0/src/monai_physio/evaluate_movement_duke_heart.py +122 -0
- monai_physio-2026.9.0/src/monai_physio/evaluate_movement_lung.py +132 -0
- monai_physio-2026.9.0/src/monai_physio/infer_physicsnemo_base.py +71 -0
- monai_physio-2026.9.0/src/monai_physio/infer_physicsnemo_mgn.py +78 -0
- monai_physio-2026.9.0/src/monai_physio/infer_physicsnemo_mlp.py +57 -0
- monai_physio-2026.9.0/src/monai_physio/monai_physio_base.py +408 -0
- monai_physio-2026.9.0/src/monai_physio/process_contours.py +1531 -0
- monai_physio-2026.9.0/src/monai_physio/process_images.py +729 -0
- monai_physio-2026.9.0/src/monai_physio/process_labelmaps.py +192 -0
- monai_physio-2026.9.0/src/monai_physio/process_landmarks.py +205 -0
- monai_physio-2026.9.0/src/monai_physio/process_physicsnemo.py +566 -0
- monai_physio-2026.9.0/src/monai_physio/process_tests.py +749 -0
- monai_physio-2026.9.0/src/monai_physio/process_transforms.py +1098 -0
- monai_physio-2026.9.0/src/monai_physio/process_usd.py +1521 -0
- monai_physio-2026.9.0/src/monai_physio/process_usd_anatomy.py +1054 -0
- monai_physio-2026.9.0/src/monai_physio/register_images_ants.py +701 -0
- monai_physio-2026.9.0/src/monai_physio/register_images_base.py +699 -0
- monai_physio-2026.9.0/src/monai_physio/register_images_chain.py +140 -0
- monai_physio-2026.9.0/src/monai_physio/register_images_greedy.py +593 -0
- monai_physio-2026.9.0/src/monai_physio/register_images_greedy_icon.py +54 -0
- monai_physio-2026.9.0/src/monai_physio/register_images_icon.py +394 -0
- monai_physio-2026.9.0/src/monai_physio/register_models_distance_maps.py +562 -0
- monai_physio-2026.9.0/src/monai_physio/register_models_icp.py +408 -0
- monai_physio-2026.9.0/src/monai_physio/register_models_icp_itk.py +422 -0
- monai_physio-2026.9.0/src/monai_physio/register_models_pca.py +1119 -0
- monai_physio-2026.9.0/src/monai_physio/register_time_series_images.py +650 -0
- monai_physio-2026.9.0/src/monai_physio/report_evaluate_movement.py +417 -0
- monai_physio-2026.9.0/src/monai_physio/segment_anatomy_base.py +475 -0
- monai_physio-2026.9.0/src/monai_physio/segment_chest_total_segmentator.py +470 -0
- monai_physio-2026.9.0/src/monai_physio/segment_chest_total_segmentator_with_contrast.py +225 -0
- monai_physio-2026.9.0/src/monai_physio/segment_heart_simpleware.py +380 -0
- monai_physio-2026.9.0/src/monai_physio/segment_heart_simpleware_trimmed_branches.py +177 -0
- monai_physio-2026.9.0/src/monai_physio/segment_nv_segment_ct_mri.py +700 -0
- monai_physio-2026.9.0/src/monai_physio/simpleware_medical/SimplewareScript_heart_segmentation.py +41 -0
- monai_physio-2026.9.0/src/monai_physio/simpleware_medical/__init__.py +10 -0
- monai_physio-2026.9.0/src/monai_physio/train_physicsnemo_base.py +555 -0
- monai_physio-2026.9.0/src/monai_physio/train_physicsnemo_mgn.py +158 -0
- monai_physio-2026.9.0/src/monai_physio/train_physicsnemo_mlp.py +92 -0
- monai_physio-2026.9.0/src/monai_physio/train_physicsnemo_physics_informed_motion.py +867 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/__init__.py +87 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/converter.py +90 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/data_structures.py +177 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/material_manager.py +183 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/mesh_utils.py +318 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/primvar_derivations.py +161 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/usd_mesh_converter.py +447 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/usd_utils.py +552 -0
- monai_physio-2026.9.0/src/monai_physio/vtk_to_usd/vtk_reader.py +701 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_convert_image_to_usd.py +469 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_convert_image_to_vtk.py +349 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_convert_vtk_to_usd.py +458 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_create_mean_surface.py +366 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_create_statistical_model.py +491 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_evaluate_movement.py +871 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_finetune_icon_registration.py +499 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_fit_statistical_model_to_patient.py +1123 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_infer_movement.py +513 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_infer_physicsnemo.py +223 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_reconstruct_highres_4d_ct.py +449 -0
- monai_physio-2026.9.0/src/monai_physio/workflow_train_physicsnemo.py +541 -0
- monai_physio-2026.9.0/src/monai_physio.egg-info/PKG-INFO +250 -0
- monai_physio-2026.9.0/src/monai_physio.egg-info/SOURCES.txt +91 -0
- monai_physio-2026.9.0/src/monai_physio.egg-info/dependency_links.txt +1 -0
- monai_physio-2026.9.0/src/monai_physio.egg-info/entry_points.txt +12 -0
- monai_physio-2026.9.0/src/monai_physio.egg-info/requires.txt +73 -0
- monai_physio-2026.9.0/src/monai_physio.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Role-based guidance for AI agents working in this repository.
|
|
4
|
+
|
|
5
|
+
MONAI Physio is a collection of methods, workflows, tutorials, and CLI tools
|
|
6
|
+
for creating personalized physiological digital twins: starting from a 3D
|
|
7
|
+
medical image of a subject, extracting anatomic models, and then using AI
|
|
8
|
+
surrogates to estimate the subject's physiological processes (initially
|
|
9
|
+
cardiac and respiratory motion, expanding to electrophysiology, blood flow,
|
|
10
|
+
and organ perfusion). It is an **early-alpha** scientific Python library.
|
|
11
|
+
Clarity beats premature optimization. Prefer compatibility: break a public API
|
|
12
|
+
only when the change is generally beneficial to future users, and record every
|
|
13
|
+
break in the migration guide (see below).
|
|
14
|
+
|
|
15
|
+
## Role
|
|
16
|
+
|
|
17
|
+
We are developing open-source code for scientific AI libraries.
|
|
18
|
+
|
|
19
|
+
**A GPU is assumed.** Supporting CPU-only machines is not a requirement.
|
|
20
|
+
Design for the GPU first and use it wherever it is faster - do not add CPU
|
|
21
|
+
fallbacks, dtype compromises, or size limits to keep a CPU-only path viable,
|
|
22
|
+
and do not weaken an algorithm because a CPU could not run it.
|
|
23
|
+
|
|
24
|
+
It follows that tests and tutorials may require a GPU. Mark those that do with
|
|
25
|
+
`@pytest.mark.requires_gpu` so the bucket stays honest, but do not contort a
|
|
26
|
+
test to avoid the marker.
|
|
27
|
+
|
|
28
|
+
## Priorities
|
|
29
|
+
|
|
30
|
+
1. Accuracy.
|
|
31
|
+
2. Clarity, maintainability, and simplicity.
|
|
32
|
+
3. Consistency with the rest of the platform and open-source standards.
|
|
33
|
+
4. Documentation.
|
|
34
|
+
5. Testing.
|
|
35
|
+
|
|
36
|
+
## Behavior
|
|
37
|
+
|
|
38
|
+
1. Do not assume. Do not hide confusion. Surface tradeoffs.
|
|
39
|
+
2. Minimum code that solves the problem. Nothing speculative.
|
|
40
|
+
3. Touch only what you must. Clean up only your own mess.
|
|
41
|
+
4. Define success criteria. Loop until verified.
|
|
42
|
+
|
|
43
|
+
## Developer Tool Prerequisites
|
|
44
|
+
|
|
45
|
+
Non-Python tools used by contributor workflows:
|
|
46
|
+
|
|
47
|
+
- **Codex CLI** (`codex`) - can run the `.agents/` slash skills and is the
|
|
48
|
+
default PR-review agent for `ai_agent_github_reviews.py`.
|
|
49
|
+
- **Claude Code CLI** (`claude`) - can run the `.agents/` slash skills and
|
|
50
|
+
`ai_agent_github_reviews.py --agent claude`.
|
|
51
|
+
Install: `winget install Anthropic.ClaudeCode`.
|
|
52
|
+
- **gh CLI** (`gh`) - required by `ai_agent_github_reviews.py` to fetch PR
|
|
53
|
+
review data. Install: `winget install GitHub.cli` then `gh auth login`.
|
|
54
|
+
Not installable via pip/uv; it is a compiled Go binary.
|
|
55
|
+
|
|
56
|
+
## Common Commands
|
|
57
|
+
|
|
58
|
+
Prefer the repository-local virtual environment at `.\venv` or `..\venv`. Activate it
|
|
59
|
+
before issuing Python commands so `python`, console scripts, and `uv pip` all use that
|
|
60
|
+
environment. If activation is not possible, invoke
|
|
61
|
+
`.\venv\Scripts\python.exe -m ...` directly. Use `uv run ...` only when the
|
|
62
|
+
local `venv` is unavailable and you need uv to create or sync an environment.
|
|
63
|
+
|
|
64
|
+
```powershell
|
|
65
|
+
# Create the repo-local environment if it does not already exist
|
|
66
|
+
uv venv venv
|
|
67
|
+
.\venv\Scripts\Activate.ps1
|
|
68
|
+
|
|
69
|
+
# Install in editable mode
|
|
70
|
+
uv pip install -e .
|
|
71
|
+
|
|
72
|
+
# Lint and format
|
|
73
|
+
python -m ruff check . --fix && python -m ruff format .
|
|
74
|
+
|
|
75
|
+
# Type checking
|
|
76
|
+
python -m mypy src/ tests/
|
|
77
|
+
|
|
78
|
+
# All pre-commit hooks
|
|
79
|
+
python -m pre_commit run --all-files
|
|
80
|
+
|
|
81
|
+
# Fast tests
|
|
82
|
+
python -m pytest tests/ -v
|
|
83
|
+
|
|
84
|
+
# Single test file or test by name
|
|
85
|
+
python -m pytest tests/test_contour_tools.py -v
|
|
86
|
+
python -m pytest tests/test_contour_tools.py::test_extract_surface -v
|
|
87
|
+
|
|
88
|
+
# Opt-in test buckets
|
|
89
|
+
python -m pytest tests/ -v --run-slow
|
|
90
|
+
python -m pytest tests/ -v --run-gpu
|
|
91
|
+
python -m pytest tests/ -v --run-simpleware
|
|
92
|
+
python -m pytest tests/ -v --run-physicsnemo
|
|
93
|
+
python -m pytest tests/ -v --run-tutorials
|
|
94
|
+
|
|
95
|
+
# Enable every bucket at once (equivalent to passing all --run-* flags)
|
|
96
|
+
python -m pytest tests/ -v --run-all
|
|
97
|
+
|
|
98
|
+
# Typical local GPU profile
|
|
99
|
+
python -m pytest tests/ -v --run-gpu --run-slow
|
|
100
|
+
|
|
101
|
+
# Coverage
|
|
102
|
+
python -m pytest tests/ --cov=src/monai_physio --cov-report=html
|
|
103
|
+
|
|
104
|
+
# Create missing baselines
|
|
105
|
+
python -m pytest tests/ --create-baselines
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Version bumping: `bumpver update --patch`, `--minor`, or `--major`.
|
|
109
|
+
|
|
110
|
+
## Migration Guide
|
|
111
|
+
|
|
112
|
+
MONAI Physio prefers compatibility. Break a public API only when the change is
|
|
113
|
+
generally beneficial to future users. Never add deprecation shims,
|
|
114
|
+
removed-symbol re-exports, or removed-symbol stubs; when a break is
|
|
115
|
+
substantial, ship code that automates the conversion instead.
|
|
116
|
+
|
|
117
|
+
At commit time: if the diff breaks a public API, append an entry to
|
|
118
|
+
`docs/developer/migration_next.md` in that same commit - what changed, why it
|
|
119
|
+
benefits future users, before/after code, and the conversion script (or
|
|
120
|
+
`None needed`). Follow the entry template at the bottom of that file.
|
|
121
|
+
|
|
122
|
+
At release time:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
bumpver update --patch
|
|
126
|
+
git mv docs/developer/migration_next.md docs/developer/migration_<new_version>.md
|
|
127
|
+
# retitle the archived file to "Migration Guide - <new_version>"
|
|
128
|
+
# recreate docs/developer/migration_next.md from its entry template
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The `Developer Guides` toctree in `docs/index.rst` globs
|
|
132
|
+
`developer/migration_*`, so archived guides need no further wiring.
|
|
133
|
+
|
|
134
|
+
## graphify
|
|
135
|
+
|
|
136
|
+
This project keeps a knowledge graph at `graphify-out/` covering god nodes,
|
|
137
|
+
community structure, and cross-file relationships. It is the recommended way
|
|
138
|
+
to navigate the codebase with an AI assistant: a scoped subgraph is far
|
|
139
|
+
smaller and more accurate than raw grep output over 8,000+ lines of source.
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
graphify query "<question>" # codebase questions -> scoped subgraph
|
|
143
|
+
graphify path "<A>" "<B>" # how two symbols relate
|
|
144
|
+
graphify explain "<concept>" # focused explanation of one concept
|
|
145
|
+
graphify update . # refresh after code changes (AST-only, no API cost)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- Prefer `graphify query` over manual searching when `graphify-out/graph.json`
|
|
149
|
+
exists.
|
|
150
|
+
- Use `graphify-out/wiki/index.md` for broad navigation, and
|
|
151
|
+
`graphify-out/GRAPH_REPORT.md` only for whole-architecture review.
|
|
152
|
+
- Run `graphify update .` after modifying code so the graph does not go stale.
|
|
153
|
+
|
|
154
|
+
## Codex Sandbox
|
|
155
|
+
|
|
156
|
+
- If a Python command fails with
|
|
157
|
+
`No Python at ...`
|
|
158
|
+
do not assume Python is missing. The sandbox can break the launcher or venv path.
|
|
159
|
+
- Use the local virtual environment instead: `.\venv`, `..\venv`, `.\.venv`, `..\.venv`
|
|
160
|
+
- Run that venv outside the sandbox when needed. Treat this as an
|
|
161
|
+
environment/sandbox workaround, not a dependency or installation problem.
|
|
162
|
+
|
|
163
|
+
## Universal Rules
|
|
164
|
+
|
|
165
|
+
- Read the relevant source files before proposing changes.
|
|
166
|
+
- Runtime classes for workflows, segmentation, registration, and USD tools
|
|
167
|
+
inherit from `MONAIPhysioBase`; new runtime classes must too. Standalone
|
|
168
|
+
utility scripts and data/container/helper classes do not.
|
|
169
|
+
- In classes that inherit from `MONAIPhysioBase`, use `self.log_info()` and
|
|
170
|
+
`self.log_debug()`, never `print()`. Standalone scripts may use `print()`.
|
|
171
|
+
- No emojis in `.py` files; avoid them in docs too. Windows cp1252 encoding
|
|
172
|
+
has broken this project before.
|
|
173
|
+
- The public VTK→USD entry point is `ConvertVTKToUSD`. Experiments, CLIs,
|
|
174
|
+
tests, and tutorials must use it. Do not import from the `vtk_to_usd/`
|
|
175
|
+
subpackage directly outside of `convert_vtk_to_usd.py` and the subpackage
|
|
176
|
+
itself.
|
|
177
|
+
- Scripts that instantiate `SegmentChestTotalSegmentator` must guard the
|
|
178
|
+
top-level invocation with `if __name__ == "__main__":` on Windows
|
|
179
|
+
(`torch.multiprocessing` requires it).
|
|
180
|
+
- When fixing a bug, fix it. Don't add a comment recording what was wrong,
|
|
181
|
+
what changed, or how it was diagnosed - that belongs in the commit message
|
|
182
|
+
or PR description, not the code. Only record it in a comment when the
|
|
183
|
+
motivation is truly exceptional: a non-obvious constraint or gotcha a
|
|
184
|
+
future editor would otherwise reintroduce.
|
|
185
|
+
- Double quotes for strings and docstrings. Keep lines at or
|
|
186
|
+
below 88 characters.
|
|
187
|
+
- Full type hints are required under strict mypy. Use `Optional[X]`, not
|
|
188
|
+
`X | None`.
|
|
189
|
+
- Run `python -m pytest tests/ -v` from the active virtual venv to verify changes.
|
|
190
|
+
Slow, GPU, Simpleware,
|
|
191
|
+
and tutorial tests are auto-skipped unless their opt-in flag is
|
|
192
|
+
passed.
|
|
193
|
+
- Do not run pytest with `--run-slow` or `--run-all` unless the user explicitly
|
|
194
|
+
asks; those runs take far too long for an interactive session. Default to the
|
|
195
|
+
fast suite and leave the opt-in buckets for the user to invoke.
|
|
196
|
+
- Query the graphify knowledge graph (`graphify query "<question>"`) to locate
|
|
197
|
+
classes, methods, and signatures before searching manually.
|
|
198
|
+
- Do not commit changes or make pull requests unless specifically told to do so.
|
|
199
|
+
|
|
200
|
+
## Data Conventions
|
|
201
|
+
|
|
202
|
+
- Images are `itk.Image` objects with axes X, Y, Z [, T] in LPS world space.
|
|
203
|
+
`itk.imread` normalizes DICOM, NIfTI, MHA, and NRRD inputs to LPS. Persist
|
|
204
|
+
images with `itk.imwrite(..., compression=True)`.
|
|
205
|
+
- 4D time series use shape `(X, Y, Z, T)`. Never silently squeeze or permute
|
|
206
|
+
axes.
|
|
207
|
+
- Surfaces are `pv.PolyData` in LPS, inherited from the source `itk.Image` via
|
|
208
|
+
`itk.vtk_image_from_image`.
|
|
209
|
+
- Convert surfaces to USD right-handed Y-up only at USD export by
|
|
210
|
+
`vtk_to_usd.lps_points_to_usd`:
|
|
211
|
+
USD `+X=Left`, `+Y=Superior`, `+Z=Anterior`.
|
|
212
|
+
- Labelmaps are ITK images with integer labels. Keep anatomy group IDs consistent
|
|
213
|
+
across segmenters.
|
|
214
|
+
- Masks are binary ITK images.
|
|
215
|
+
- Transforms are ITK composite transforms stored in compressed `.hdf` files.
|
|
216
|
+
- These conventions are fixed and hold everywhere. This section is their single
|
|
217
|
+
source of truth - do not restate them in docstrings, comments, or test
|
|
218
|
+
docstrings. Document only genuine deviations, such as a raw NumPy array whose
|
|
219
|
+
axes are reversed relative to the ITK image it came from.
|
|
220
|
+
|
|
221
|
+
## Implementation Role
|
|
222
|
+
|
|
223
|
+
- Summarize current behavior in 2-4 sentences before editing.
|
|
224
|
+
- Identify success criteria or metrics.
|
|
225
|
+
- Refer to `*_tools.py` files for commonly used routines.
|
|
226
|
+
- Refer to `workspace/reference_code`, when available, for third-party library
|
|
227
|
+
usage.
|
|
228
|
+
- Propose a numbered plan; confirm before implementing non-trivial structural
|
|
229
|
+
changes.
|
|
230
|
+
- Keep diffs small and reviewable.
|
|
231
|
+
- Prefer editing existing modules over creating new ones.
|
|
232
|
+
- No deprecation shims, removed-symbol re-exports, or removed-symbol stubs.
|
|
233
|
+
Change the code, log the break in `docs/developer/migration_next.md`, and
|
|
234
|
+
provide a conversion script when the change is substantial.
|
|
235
|
+
|
|
236
|
+
## Testing Role
|
|
237
|
+
|
|
238
|
+
- Strongly prefer real downloaded test data over synthetic data. Request the
|
|
239
|
+
session fixtures `test_directories`, `download_test_data`, and `test_images`
|
|
240
|
+
so standard datasets are fetched automatically on first use.
|
|
241
|
+
- Real data exercises preprocessing, resampling, dtype handling, and
|
|
242
|
+
world-frame metadata paths that synthetic toy volumes silently bypass.
|
|
243
|
+
- Only fall back to synthetic `itk.Image` or `pv.PolyData` inputs when the
|
|
244
|
+
behavior under test is a pure unit such as axis arithmetic or dict routing,
|
|
245
|
+
or when real data would push the test into a slow, GPU, or Simpleware bucket
|
|
246
|
+
that does not fit the test's purpose. Keep synthetic volumes at or below 64
|
|
247
|
+
voxels per side and say so in the docstring.
|
|
248
|
+
- Do not restate ITK shape, axis order, or world frame in test docstrings -
|
|
249
|
+
those are fixed conventions (see Data Conventions above). State only what is
|
|
250
|
+
specific to the test, such as the size of a synthetic volume.
|
|
251
|
+
- When a test produces an image or surface, compare against a baseline using
|
|
252
|
+
`src/monai_physio/process_tests.py` utilities such as `ProcessTests`.
|
|
253
|
+
- Store baselines under `tests/baselines/`, which is tracked by Git LFS. Run
|
|
254
|
+
`git lfs pull` after cloning.
|
|
255
|
+
- Run with `--create-baselines` to materialize missing baselines on first use.
|
|
256
|
+
- `tests/conftest.py` owns session-scoped fixtures that chain download,
|
|
257
|
+
convert, segment, and register.
|
|
258
|
+
- Mark tests that need a GPU, a slow runtime, or a licensed Simpleware install
|
|
259
|
+
with `@pytest.mark.requires_gpu`, `@pytest.mark.slow`, or
|
|
260
|
+
`@pytest.mark.requires_simpleware`.
|
|
261
|
+
- Mark tutorial tests with `@pytest.mark.tutorial`.
|
|
262
|
+
- Tests that just need downloadable data need no marker; the fixture chain
|
|
263
|
+
handles it.
|
|
264
|
+
- Prefer images from `ROOT/data/test/slicer_heart_small` for tests.
|
|
265
|
+
- Prefer storing test results in subdirectories under `./results/<test_name>`.
|
|
266
|
+
|
|
267
|
+
## Documentation Role
|
|
268
|
+
|
|
269
|
+
- Update docstrings for every changed public method. Keep claims factual.
|
|
270
|
+
- Document with docstrings and inline comments.
|
|
271
|
+
- Do not restate the fixed ITK shape, axis-order, or LPS conventions in
|
|
272
|
+
docstrings. Document only genuine deviations, such as a raw NumPy array whose
|
|
273
|
+
axes are reversed relative to the ITK image it came from.
|
|
274
|
+
- Do not create new `.md` files unless explicitly requested.
|
|
275
|
+
- Refresh the graphify knowledge graph after any public API change:
|
|
276
|
+
`graphify update .`.
|
|
277
|
+
|
|
278
|
+
## Architecture Role
|
|
279
|
+
|
|
280
|
+
- Propose a numbered design plan with tradeoffs before structural changes.
|
|
281
|
+
- Identify every file that will change and how the class hierarchy is affected.
|
|
282
|
+
- Flag changes at the ITK/PyVista boundary, which stays in the internal LPS
|
|
283
|
+
frame, or the LPS to USD Y-up export transform as high-risk.
|
|
284
|
+
|
|
285
|
+
## File Operations
|
|
286
|
+
|
|
287
|
+
- Use `git mv` and `git rm`, not `mv` or `rm`, to preserve history.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Project guidance for Claude Code in this repository.
|
|
4
|
+
|
|
5
|
+
## Role
|
|
6
|
+
|
|
7
|
+
We are developing open-source code for scientific AI libraries.
|
|
8
|
+
|
|
9
|
+
**A GPU is assumed.** Supporting CPU-only machines is not a requirement.
|
|
10
|
+
Design for the GPU first and use it wherever it is faster - do not add CPU
|
|
11
|
+
fallbacks, dtype compromises, or size limits to keep a CPU-only path viable,
|
|
12
|
+
and do not weaken an algorithm because a CPU could not run it.
|
|
13
|
+
|
|
14
|
+
It follows that tests and tutorials may require a GPU. Mark those that do with
|
|
15
|
+
`@pytest.mark.requires_gpu` so the bucket stays honest, but do not contort a
|
|
16
|
+
test to avoid the marker.
|
|
17
|
+
|
|
18
|
+
## 1. Think Before Coding
|
|
19
|
+
|
|
20
|
+
**Don't assume. Don't hide confusion. Surface tradeoffs.**
|
|
21
|
+
|
|
22
|
+
Before implementing:
|
|
23
|
+
|
|
24
|
+
- State your assumptions explicitly. If uncertain, ask.
|
|
25
|
+
- If multiple interpretations exist, present them - don't pick silently.
|
|
26
|
+
- If a simpler approach exists, say so. Push back when warranted.
|
|
27
|
+
- If something is unclear, stop. Name what's confusing. Ask.
|
|
28
|
+
|
|
29
|
+
## 2. Simplicity First
|
|
30
|
+
|
|
31
|
+
**Minimum code that solves the problem. Nothing speculative.**
|
|
32
|
+
|
|
33
|
+
- No features beyond what was asked.
|
|
34
|
+
- No abstractions for single-use code.
|
|
35
|
+
- No "flexibility" or "configurability" that wasn't requested.
|
|
36
|
+
- No error handling for impossible scenarios.
|
|
37
|
+
- If you write 200 lines and it could be 50, rewrite it.
|
|
38
|
+
|
|
39
|
+
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
|
|
40
|
+
|
|
41
|
+
## 3. Surgical Changes
|
|
42
|
+
|
|
43
|
+
**Touch only what you must. Clean up only your own mess.**
|
|
44
|
+
|
|
45
|
+
When editing existing code:
|
|
46
|
+
|
|
47
|
+
- Don't "improve" adjacent code, comments, or formatting.
|
|
48
|
+
- Don't refactor things that aren't broken.
|
|
49
|
+
- Match existing style, even if you'd do it differently.
|
|
50
|
+
- If you notice unrelated dead code, mention it - don't delete it.
|
|
51
|
+
- When fixing a bug, fix it. Don't add a comment narrating what was wrong,
|
|
52
|
+
what changed, or how it was diagnosed - the commit message and PR
|
|
53
|
+
description are where that belongs, not the code. Only record it in a
|
|
54
|
+
comment when the motivation is truly exceptional: a non-obvious constraint
|
|
55
|
+
or gotcha a future editor would otherwise reintroduce.
|
|
56
|
+
|
|
57
|
+
When your changes create orphans:
|
|
58
|
+
|
|
59
|
+
- Remove imports/variables/functions that YOUR changes made unused.
|
|
60
|
+
- Don't remove pre-existing dead code unless asked.
|
|
61
|
+
|
|
62
|
+
The test: Every changed line should trace directly to the user's request.
|
|
63
|
+
|
|
64
|
+
## 4. Goal-Driven Execution
|
|
65
|
+
|
|
66
|
+
**Define success criteria. Loop until verified.**
|
|
67
|
+
|
|
68
|
+
Transform tasks into verifiable goals:
|
|
69
|
+
|
|
70
|
+
- "Add validation" → "Write tests for invalid inputs, then make them pass"
|
|
71
|
+
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
|
|
72
|
+
- "Refactor X" → "Ensure tests pass before and after"
|
|
73
|
+
|
|
74
|
+
For multi-step tasks, state a brief plan:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
1. [Step] → verify: [check]
|
|
78
|
+
2. [Step] → verify: [check]
|
|
79
|
+
3. [Step] → verify: [check]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Strong success criteria let you loop independently. Weak criteria
|
|
83
|
+
("make it work") require constant clarification.
|
|
84
|
+
|
|
85
|
+
## 5. Project-Specific Rules
|
|
86
|
+
|
|
87
|
+
- Prefer compatibility. Break a public API only when the change is generally
|
|
88
|
+
beneficial to future users.
|
|
89
|
+
- Never add deprecation shims, removed-symbol re-exports, or removed-symbol
|
|
90
|
+
stubs. When a break is substantial, ship code that automates the conversion
|
|
91
|
+
instead.
|
|
92
|
+
- Every commit that breaks a public API must add an entry to
|
|
93
|
+
`docs/developer/migration_next.md`: what changed, why it benefits future
|
|
94
|
+
users, before/after code, and the conversion script (or `None needed`).
|
|
95
|
+
- At release time, `git mv docs/developer/migration_next.md
|
|
96
|
+
docs/developer/migration_<version>.md`, retitle it, and start a fresh
|
|
97
|
+
`migration_next.md` from its entry template.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
**These guidelines are working if:** fewer unnecessary changes in diffs,
|
|
102
|
+
fewer rewrites due to overcomplication, and clarifying questions come
|
|
103
|
+
before implementation rather than after mistakes.
|
|
104
|
+
|
|
105
|
+
## Commands
|
|
106
|
+
|
|
107
|
+
**Python launcher:** Use `py` on this Windows system (not `python`).
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Install in editable mode (preferred)
|
|
111
|
+
uv pip install -e .[dev]
|
|
112
|
+
|
|
113
|
+
# Lint and format
|
|
114
|
+
ruff check . --fix && ruff format .
|
|
115
|
+
|
|
116
|
+
# Type checking
|
|
117
|
+
mypy src/ tests/
|
|
118
|
+
|
|
119
|
+
# All pre-commit hooks
|
|
120
|
+
pre-commit run --all-files
|
|
121
|
+
|
|
122
|
+
**Version bumping:** `bumpver update --patch` (or `--minor`, `--major`)
|
|
123
|
+
|
|
124
|
+
## Architecture
|
|
125
|
+
|
|
126
|
+
All classes inherit from `MONAIPhysioBase` (`monai_physio_base.py`),
|
|
127
|
+
which provides a shared logger. Use `self.log_info()`, `self.log_debug()`
|
|
128
|
+
- never `print()`.
|
|
129
|
+
|
|
130
|
+
Use graphify (see section below) to locate classes, methods, and signatures.
|
|
131
|
+
|
|
132
|
+
**Key data conventions:**
|
|
133
|
+
|
|
134
|
+
- Images: `itk.Image`, axes X, Y, Z [, T] in LPS world space (ITK's native
|
|
135
|
+
frame; `itk.imread` normalizes DICOM, NIfTI, MHA, and NRRD inputs to LPS)
|
|
136
|
+
stored using itk.imwrite with compression=True
|
|
137
|
+
- never silently squeeze or permute axes
|
|
138
|
+
- Surfaces: `pv.PolyData` in LPS (inherited from the source `itk.Image` via
|
|
139
|
+
`itk.vtk_image_from_image`); converted to USD right-handed Y-up only at USD
|
|
140
|
+
export by `vtk_to_usd.lps_points_to_usd` (USD +X=Left, +Y=Superior, +Z=Anterior)
|
|
141
|
+
- Labelmaps: ITK images with integer labels defined by anatomy segmenter used.
|
|
142
|
+
- Masks: ITK binary images
|
|
143
|
+
- Transforms: ITK transforms stored in `.hdf` files with compression
|
|
144
|
+
|
|
145
|
+
These conventions are fixed and hold everywhere, so this list is their single
|
|
146
|
+
source of truth - do not restate shape, axis order, or world space in
|
|
147
|
+
docstrings, comments, or test docstrings. Document only genuine deviations,
|
|
148
|
+
such as a raw NumPy array whose axes are reversed relative to the ITK image it
|
|
149
|
+
came from.
|
|
150
|
+
|
|
151
|
+
## Testing
|
|
152
|
+
|
|
153
|
+
- Fast tests (recommended for development - slow/GPU/Simpleware/tutorial
|
|
154
|
+
tests are auto-skipped unless their opt-in flag is passed)
|
|
155
|
+
py -m pytest tests/ -v
|
|
156
|
+
- Baselines in `tests/baselines/` via Git LFS - run `git lfs pull` after cloning
|
|
157
|
+
- `tests/conftest.py`: session-scoped fixtures chaining
|
|
158
|
+
download → convert → segment → register
|
|
159
|
+
- `src/monai_physio/process_tests.py`: baseline comparison utilities (`ProcessTests`, etc.)
|
|
160
|
+
- Markers (all opt-in via `--run-<bucket>`): `slow`, `requires_gpu`,
|
|
161
|
+
`requires_simpleware`, `tutorial`. Data-dependent tests no
|
|
162
|
+
longer use a marker - they pull data through fixtures and run by default.
|
|
163
|
+
- `experiments/` scripts are exploratory and are not run as tests; the
|
|
164
|
+
`tutorials/` scripts are the optional end-to-end suite
|
|
165
|
+
- **Avoid `pytest --run-slow` (or `--run-all`) unless the user explicitly
|
|
166
|
+
requests it.** Those runs take far too long for an interactive session.
|
|
167
|
+
Default to the fast suite and let the user invoke the slow buckets.
|
|
168
|
+
- Prefer images from `ROOT/data/test/slicer_heart_small` for tests
|
|
169
|
+
- Prefer storing results in subdirs `./results/<test_name>`
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
## Agents and Skills
|
|
173
|
+
|
|
174
|
+
Role-specific subagents live in `.agents/agents/`; slash-command skills in
|
|
175
|
+
`.agents/skills/`. See `AGENTS.md` for role-based guidance that applies across
|
|
176
|
+
Claude, Codex, and other AI tooling.
|
|
177
|
+
|
|
178
|
+
- `/plan` - inspect files, summarize design, produce a numbered plan (no code changes)
|
|
179
|
+
- `/impl` - read → summarize → plan → implement in small diffs
|
|
180
|
+
- `/test-feature` - propose test plan, write real-data-driven pytest tests
|
|
181
|
+
with baselines
|
|
182
|
+
- `/doc-feature` - update docstrings
|
|
183
|
+
- `/check-conventions` - audit changed files against project hard rules
|
|
184
|
+
(base-class, logging, coordinate frame, USD entry point, Windows mp guard,
|
|
185
|
+
quoting, type hints, line length, emoji ban)
|
|
186
|
+
- `/simplify-staged` - readability / quality pass over `git diff HEAD`
|
|
187
|
+
- `/commit` - stage tracked changes, draft `<TAG>: …` message, loop until hooks pass
|
|
188
|
+
- `/review-pr <NUMBER>` - drive `utils/ai_agent_github_reviews.py` to triage
|
|
189
|
+
a PR's review comments and apply accepted edits as pending changes
|
|
190
|
+
|
|
191
|
+
## File Operations
|
|
192
|
+
|
|
193
|
+
Use `git mv` / `git rm` - not `mv` / `rm` - to preserve history.
|
|
194
|
+
|
|
195
|
+
## Documentation Policy
|
|
196
|
+
|
|
197
|
+
Do **not** create new `.md` files unless explicitly requested.
|
|
198
|
+
Document via docstrings and inline comments.
|
|
199
|
+
|
|
200
|
+
Exception: the migration guide. Append to `docs/developer/migration_next.md`
|
|
201
|
+
whenever a commit breaks a public API, and create
|
|
202
|
+
`docs/developer/migration_<version>.md` plus a fresh `migration_next.md` at
|
|
203
|
+
release time.
|
|
204
|
+
|
|
205
|
+
## Code Style
|
|
206
|
+
|
|
207
|
+
- Double quotes for strings and docstrings
|
|
208
|
+
- Full type hints (`mypy` strict; `disallow_untyped_defs = true`)
|
|
209
|
+
- `Optional[X]` not `X | None` (ruff `UP007` suppressed)
|
|
210
|
+
- Max line length: 88 characters
|
|
211
|
+
- Follow behavior guidelines.
|
|
212
|
+
|
|
213
|
+
## graphify
|
|
214
|
+
|
|
215
|
+
This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.
|
|
216
|
+
|
|
217
|
+
Rules:
|
|
218
|
+
|
|
219
|
+
- For codebase questions, first run `graphify query "<question>"` when graphify-out/graph.json exists. Use `graphify path "<A>" "<B>"` for relationships and `graphify explain "<concept>"` for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output.
|
|
220
|
+
- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
|
|
221
|
+
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
|
|
222
|
+
- After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost).
|