blochtwin 0.3.1__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.
Files changed (51) hide show
  1. blochtwin-0.3.1/.gitignore +34 -0
  2. blochtwin-0.3.1/CHANGELOG.md +164 -0
  3. blochtwin-0.3.1/CITATION.cff +44 -0
  4. blochtwin-0.3.1/LICENSE +24 -0
  5. blochtwin-0.3.1/NOTICE +11 -0
  6. blochtwin-0.3.1/PKG-INFO +197 -0
  7. blochtwin-0.3.1/README.md +123 -0
  8. blochtwin-0.3.1/blochtwin/__init__.py +100 -0
  9. blochtwin-0.3.1/blochtwin/_version.py +6 -0
  10. blochtwin-0.3.1/blochtwin/backend.py +201 -0
  11. blochtwin-0.3.1/blochtwin/bloch/__init__.py +46 -0
  12. blochtwin-0.3.1/blochtwin/bloch/engine.py +189 -0
  13. blochtwin-0.3.1/blochtwin/bloch/isochromat.py +56 -0
  14. blochtwin-0.3.1/blochtwin/bloch/operators.py +124 -0
  15. blochtwin-0.3.1/blochtwin/cli.py +281 -0
  16. blochtwin-0.3.1/blochtwin/io/__init__.py +31 -0
  17. blochtwin-0.3.1/blochtwin/io/download.py +300 -0
  18. blochtwin-0.3.1/blochtwin/io/ismrmrd_io.py +120 -0
  19. blochtwin-0.3.1/blochtwin/kspace/__init__.py +23 -0
  20. blochtwin-0.3.1/blochtwin/kspace/encoding.py +102 -0
  21. blochtwin-0.3.1/blochtwin/phantom/__init__.py +21 -0
  22. blochtwin-0.3.1/blochtwin/phantom/phantom.py +200 -0
  23. blochtwin-0.3.1/blochtwin/phantom/sources.py +108 -0
  24. blochtwin-0.3.1/blochtwin/phantom/synthetic.py +231 -0
  25. blochtwin-0.3.1/blochtwin/physics/__init__.py +33 -0
  26. blochtwin-0.3.1/blochtwin/physics/tables.py +314 -0
  27. blochtwin-0.3.1/blochtwin/physics/tissue.py +57 -0
  28. blochtwin-0.3.1/blochtwin/recon/__init__.py +11 -0
  29. blochtwin-0.3.1/blochtwin/recon/cartesian.py +19 -0
  30. blochtwin-0.3.1/blochtwin/sequence/__init__.py +37 -0
  31. blochtwin-0.3.1/blochtwin/sequence/families.py +364 -0
  32. blochtwin-0.3.1/blochtwin/sequence/rf.py +76 -0
  33. blochtwin-0.3.1/blochtwin/sequence/sequence.py +188 -0
  34. blochtwin-0.3.1/blochtwin/simulator.py +206 -0
  35. blochtwin-0.3.1/blochtwin/viz/__init__.py +13 -0
  36. blochtwin-0.3.1/blochtwin/viz/inspect.py +58 -0
  37. blochtwin-0.3.1/blochtwin/viz/sequence_plot.py +63 -0
  38. blochtwin-0.3.1/examples/README.md +24 -0
  39. blochtwin-0.3.1/examples/quickstart.py +98 -0
  40. blochtwin-0.3.1/examples/simulate_mvp.py +64 -0
  41. blochtwin-0.3.1/pyproject.toml +100 -0
  42. blochtwin-0.3.1/tests/test_backend.py +66 -0
  43. blochtwin-0.3.1/tests/test_bloch.py +151 -0
  44. blochtwin-0.3.1/tests/test_ismrmrd_io.py +49 -0
  45. blochtwin-0.3.1/tests/test_package.py +62 -0
  46. blochtwin-0.3.1/tests/test_phantom.py +108 -0
  47. blochtwin-0.3.1/tests/test_phantom_sources.py +108 -0
  48. blochtwin-0.3.1/tests/test_physics_tables.py +119 -0
  49. blochtwin-0.3.1/tests/test_sequence_families.py +110 -0
  50. blochtwin-0.3.1/tests/test_sequence_io.py +69 -0
  51. blochtwin-0.3.1/tests/test_simulate.py +100 -0
@@ -0,0 +1,34 @@
1
+ .DS_Store
2
+ **/.DS_Store
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.egg-info/
8
+ .eggs/
9
+ build/
10
+ dist/
11
+ *.so
12
+
13
+ # Virtual environments
14
+ .venv/
15
+ venv/
16
+ env/
17
+
18
+ # Test / coverage / cache
19
+ .pytest_cache/
20
+ .ruff_cache/
21
+ .coverage
22
+ htmlcov/
23
+ .mypy_cache/
24
+
25
+ # Generated artifacts (phantoms, sequences, raw data) — never commit data
26
+ *.npz
27
+ *.seq
28
+ *.h5
29
+ *.nii
30
+ *.nii.gz
31
+ !references/**
32
+
33
+ # Local datasets (third-party, never commit)
34
+ data/
@@ -0,0 +1,164 @@
1
+ # Changelog
2
+
3
+ 이 프로젝트는 [Semantic Versioning](https://semver.org)을 따릅니다(pre-1.0에서는 minor = 마일스톤).
4
+ 릴리스 노트는 "무엇이 새로운가 · 연구자가 할 수 있는 것 · 구현한 물리와 논문" 순서로 씁니다.
5
+
6
+ ## [0.3.1] — 2026-10-29 · BlochTwin으로 이름 변경 · PyPI 첫 배포
7
+
8
+ ### 이름 변경: PhantomMRI → **BlochTwin** · PyPI 첫 배포
9
+ - 패키지와 import 이름은 `blochtwin`(`pip install blochtwin`, `import blochtwin as bt`), CLI는 `blochtwin`.
10
+ - 이름을 바꾼 이유: MRI에서 "phantom"은 QA용 실물 팬텀을 가리켜 검색 결과와 의미가 겹친다. 새 이름은
11
+ Bloch 방정식으로 스캐너를 재현하는 디지털 트윈이라는 정체성을 드러낸다.
12
+
13
+ ### 시퀀스 패밀리 추가: FLAIR / Inversion Recovery
14
+ - **`InversionRecovery`** (180° invert → TI → 90°–180° SE readout) + **`FLAIR`** preset:
15
+ 반전회복으로 특정 조직을 null하고 SE로 T2 가중을 얹음. STIR(지방 null)·T1-FLAIR·FLAIR(CSF
16
+ null)가 모두 같은 물리(TI/TE만 다름).
17
+ - **`FLAIR`** 기본값(3T): TI 2500 ms로 **CSF를 null**(T1≈4300ms, TR 9000ms), TE 90 ms T2 가중.
18
+ 결과: CSF가 어둡게, 뇌조직은 T2 가중(병변 강조) — 임상 FLAIR 대비와 일치. 검증: CSF 신호
19
+ < WM의 10%, IR-SE 엔진 vs 닫힌 해 0.000%(null 근처 제외).
20
+ - **`null_ti_ms(t1, tr)`** 헬퍼: 임의 조직/필드의 null TI 계산(유한 TR 보정 포함).
21
+ - CLI: `blochtwin simulate --seq flair`(또는 `--seq ir --ti …`).
22
+
23
+ ### 팬텀 소스 선택 (실제 사람 머리 해부 경로)
24
+ - **절차적 팬텀에 공기강 추가**(`build_brain_phantom(sinuses=True)` 기본): 비강·상악/전두/
25
+ 접형 부비동·이도(ear canal) 공기 주머니를 carve → 공기/조직 경계 생성(M3 susceptibility 대비).
26
+ - **팬텀 소스 registry + 통합 API**(`bt.load_phantom(source=...)`, `bt.list_phantom_sources()`):
27
+ `procedural`(내장) / `brainweb`(실제 뇌) / `nyhead`(실제 머리: scalp/skull/CSF/GM/WM/공기) 중
28
+ 선택. 외부 소스는 **번들 금지**·라이선스 게이트.
29
+ - **New York Head 로더**(`load_nyhead`) + 일반 분할 머리 로더(`load_segmented_head`):
30
+ 6구획 분할(부비동·콧구멍 공기 포함)을 9조직으로 매핑 — 정확히 "skin+bone+skull(공기강)" 충족.
31
+ 실데이터는 사용자가 다운로드(`nyhead_license_notice()`), 로딩/매핑 로직은 합성 fixture로 검증.
32
+ - CLI: `blochtwin phantom --source {procedural,brainweb,nyhead} [--path …] [--list-sources]`.
33
+ - 테스트 89개 통과. ROADMAP M1의 "New York Head 흡수 검토" → 로더 구현 완료.
34
+
35
+ ## [0.3.0] — 2026-06-10 · MVP: Bloch 시뮬 + k-space + recon (M2) ⭐
36
+
37
+ **시뮬레이터의 심장 완성.** 파라미터 → **물리적으로 올바른 복소 k-space → 영상**이 한 바퀴
38
+ 돕니다. 외부 연구자에게 처음으로 쓸모 있어지는 MVP 라인입니다. 대비(T1/T2/T2* weighting)는
39
+ 하드코딩이 아니라 Bloch 물리에서 자연히 나옵니다.
40
+
41
+ ### 무엇이 새로운가
42
+ - **Forward 시뮬레이터**(`simulate`): 팬텀 + GRE/SE 시퀀스 → 복소 k-space → iFFT recon 영상,
43
+ 결정론적 스캔타임. 코일 1개·full-Cartesian.
44
+ - **operator-splitting Bloch 엔진**(`blochtwin.bloch`): 회전(Rodrigues) ∘ 이완으로 분해,
45
+ PyTorch **미분 가능**. GRE/SE 정상상태 신호의 **해석적 닫힌 해와 기계정밀도로 일치**.
46
+ - **T2\* = 가역 vs 비가역 디페이징**: 비가역 T2 위에 가역 R2'=1/T2*−1/T2를 얹고, 180° 펄스가
47
+ R2'를 refocus. GRE(refocus 없음)는 T2\*, SE는 T2 — **대비가 refocusing 구조에서 emergent**.
48
+ (literal isochromat 앙상블 경로도 `mode="isochromat"`로 제공.)
49
+ - **시퀀스 패밀리 GRE·SE**(`GradientEcho`/`SpinEcho`): Bloch 이벤트 타임라인 + Pulseq `.seq` +
50
+ 해석적 닫힌 해 + 스캔타임을 한 파라미터셋에서 모두 도출.
51
+ - **교체 가능 RF shape**(`RFPulse`): apodized sinc + slice-rephasing, TBW 파라미터화.
52
+ - **k-space + recon**: image→k-space FFT + 매트릭스 크롭(유한 해상도·Gibbs 자연 발생),
53
+ Cartesian iFFT recon, 선택적 복소 가우시안 k-space 노이즈(→ Rician).
54
+ - **시퀀스 뷰어 + 결과 표시**(`blochtwin.viz`, lazy matplotlib), CLI `simulate` 명령.
55
+
56
+ ### 연구자가 할 수 있는 것
57
+ - TR/TE/flip/FOV/matrix/필드세기를 바꿔 GRE(T2\*/T1 가중)·SE(T2 가중) 영상을 직접 생성.
58
+ - 복소 k-space·영상·조직별 정상상태 신호·정확한 스캔타임을 한 번에 획득(기초 합성 데이터).
59
+ - `blochtwin simulate --seq se --te 90` 한 줄로 T2 가중 영상 + 스캔타임 확인.
60
+ - diff-MRI: 신호가 flip 등에 미분 가능(autograd 그래프 보존).
61
+
62
+ ### 구현한 물리·논문
63
+ - **Bloch 방정식** — *Bloch 1946.* **연산자 분리** — *Lauzon 2020 · SIMRI (Benoit-Cattin 2005).*
64
+ - **k-space = gradient 적분, 신호 = Fourier 샘플** — *Twieg 1983 · Ljunggren 1983.*
65
+ - **GRE/SE 정상상태 신호식** — 표준 공학 텍스트(Nishimura; Bernstein-King-Zhou).
66
+ - **영상 노이즈 = k-space 복소 가우시안 → Rician** — *Gudbjartsson-Patz 1995.*
67
+ - 미분 가능 코어 정신 — *MRzero (Loktyushin 2021) · PDG (Endres 2024).*
68
+
69
+ ### 검증 결과 (`pytest`, 79 passed)
70
+ - **충실도 게이트 (KomaMRI 수치 대조 완료):** KomaMRI.jl(Castillo-Passi 2023)을 실제로 설치해
71
+ 동일 단일-voxel 실험(spin echo=T2, inversion recovery=T1, flip angle=excitation; WM/GM/CSF)을
72
+ 대조 → **BlochTwin vs KomaMRI mean-abs-diff = 0.0023% (worst 0.011%), 게이트 <0.1% 통과.**
73
+ BlochTwin은 해석적 Bloch 식과 기계정밀도(0.000%)로 일치. 재현: `benchmarks/compare.py`.
74
+ (정상상태 spoiled GRE는 spoiling 모델 차이 — 우리는 ideal spoiling=Ernst 정확, Koma는 유한
75
+ isochromat gradient spoiling이라 잔류 coherence 수% — 물리 불일치 아님. T2\*는 양쪽 모두
76
+ isochromat 필요. `benchmarks/README.md` 참조.) isochromat 모드는 T2\* 닫힌 해에 <1% 수렴.
77
+ - **대비가 emergent:** SE T2 가중에서 CSF가 가장 밝고, 단TR GRE에서 WM>CSF로 **순서가 시퀀스에
78
+ 따라 뒤집힘**(하드코딩 아님). 필드세기 토글이 WM 신호를 바꿈.
79
+ - **수치:** encode/recon round-trip 기계정밀도, 스캔타임 = TR×N_PE×N_avg 단위테스트, 노이즈
80
+ 재현성(seed), `.seq` timing 유효, 미분 가능성(∂|Mxy|/∂flip = cos α).
81
+
82
+ ### 알려진 한계 / 근사
83
+ - 단일 코일·full-Cartesian·2D 단일 슬라이스. 멀티코일/병렬영상은 M4(v0.5.0).
84
+ - 음향 노이즈·모션/Gibbs/chemical-shift/susceptibility 아티팩트는 M3(v0.4.0).
85
+ - in-plane FOV는 팬텀 슬라이스를 따르고 매트릭스가 해상도를 정함(FOV zoom은 후속).
86
+ - T2\* 기본 경로는 가역/비가역 분리 해석 모델(정확). isochromat 경로는 이산화 오차(개수 의존).
87
+ - KomaMRI **수치** 대조 완료(0.0023%, `benchmarks/`). JEMRIS 대조는 후속.
88
+
89
+ ### 설치·예제
90
+ ```bash
91
+ pip install blochtwin
92
+ python examples/simulate_mvp.py # 파라미터→k-space→영상, 대비 demo
93
+ blochtwin simulate --seq se --te 90 # CLI 한 줄
94
+ ```
95
+
96
+ ### 인용
97
+ [CITATION.cff](CITATION.cff) (v0.3.0). Zenodo version DOI와 arXiv preprint는 이 릴리스 라인에 맞춰
98
+ 발행할 예정입니다.
99
+
100
+ ## [0.2.0] — 2026-06-10 · 기반 + 팬텀 (M0 + M1) · 조용한 공개
101
+
102
+ **코드 첫 버전.** 외부 표준과 배포
103
+ 구조를 못 박고, 시뮬레이터가 먹을 "디지털 객체"인 3D fuzzy 뇌 팬텀을 만들었습니다.
104
+ **아직 신호(Bloch) 시뮬레이션은 없습니다** — 그건 v0.3.0 MVP입니다.
105
+
106
+ ### 무엇이 새로운가
107
+ - `blochtwin` headless 수치 코어 패키지(라이브러리 + `blochtwin` CLI). 코어는 **GUI를
108
+ import하지 않습니다**(클러스터 headless 실행 보장, 테스트로 강제).
109
+ - **PyTorch 백엔드 추상화**(`get_backend`): CPU/CUDA/MPS 디바이스 + dtype 해석. 데이터 생성
110
+ 기본값은 **CPU/CUDA float64**, MPS는 교육용 float32 경로로만 — 정밀도 정책을 코드로 강제
111
+ (MPS+float64 / MPS+데이터 생성은 에러).
112
+ - **3D fuzzy 뇌 팬텀**(`build_brain_phantom`): ICBM152-유사 격자 위 9개 조직 클래스
113
+ (WM/GM/CSF/skull/skin/fat/glial/connective/background)의 분율 맵. 절차적·결정론적 생성이라
114
+ 외부 데이터 없이 바로 돌아갑니다. 부드러운 경계 = partial-volume(경계 voxel이 혼합값).
115
+ - **필드세기별 조직 파라미터 테이블**(`tissue_parameters`, `tissue_table`): 1.5/3/7T의
116
+ T1/T2/T2*/PD/χ를 **출처 태깅과 함께** 제공. Rooney power-law T1(B0), Peters T2*, 화학적
117
+ 이동(`chemical_shift_hz`). 7T·glial/connective/skin 값은 정직하게 플래그.
118
+ - **Pulseq `.seq` I/O**(`read_seq`/`write_seq`): PyPulseq 1.5 재사용(직접 재발명 안 함).
119
+ 데모 GRE 빌더 포함(round-trip·뷰어용).
120
+ - **ISMRMRD 출력 스텁**(`write_ismrmrd_skeleton`): 유효한 XML 헤더 + HDF5, 표준 리더로 다시
121
+ 열림.
122
+ - **BrainWeb/ICBM 다운로더·로더**(`blochtwin.io.download`): 외부 팬텀은 **번들하지 않고**
123
+ 사용자가 라이선스 동의 후 받아 같은 `Phantom`으로 적재.
124
+ - **napari 3D 인스펙터**(선택, `blochtwin[viz]`, lazy import).
125
+ - pip extras 골격(`[cuda]/[viz]/[ml]/[app]/[dev]`) + 재현용 Docker 스텁.
126
+
127
+ ### 연구자가 할 수 있는 것
128
+ - `pip install blochtwin` 후 fuzzy 조직 분율 팬텀을 만들고 검사(napari).
129
+ - 1.5/3/7T 조직 파라미터 테이블을 인용 출처와 함께 조회(`blochtwin tables --field 7.0`).
130
+ - Pulseq `.seq`를 읽고/쓰고 round-trip 검증, 빈 ISMRMRD 파일을 표준 리더로 열기.
131
+
132
+ ### 구현한 물리·논문
133
+ - **부분 체적(partial volume):** voxel 신호 = 조직별 분율 가중합, Σ f_k = 1 —
134
+ *BrainWeb (Collins 1998; Kwan 1999; Aubert-Broche 2006).*
135
+ - **필드 의존 T1 power-law:** WM ≈ 0.583·B0^0.382 s, GM ≈ 0.857·B0^0.376 s, CSF ≈ 4.3 s
136
+ (≈ B0-무관) — *Rooney 2007.*
137
+ - **멀티필드 T2\*** — *Peters 2007.* 3T 이완 앵커 — *Stanisz 2005, Wansapura 1999.*
138
+ 자화율 χ — *Schenck 1996.* 화학적 이동 Δf = ppm·γ̄·B0.
139
+
140
+ ### 검증 결과 (`pytest`, 48 passed)
141
+ - 팬텀: 분율 합이 voxel당 1에서 최대 ~1e-16 이내, 분율 ∈ [0,1], WM/GM 경계 혼합 voxel 존재.
142
+ - 물리 테이블: 3T WM T1 ≈ 832 ms, GM ≈ 1331 ms, CSF ≈ 4300 ms(인용 범위 내), T1은 필드와
143
+ 함께 증가·T2\*는 감소, 모든 값이 출처를 가짐.
144
+ - Pulseq round-trip: 써놓은 `.seq`를 다시 읽어 쓰면 body·서명·duration·k-space 샘플 수 일치.
145
+ - ISMRMRD: 스켈레톤이 표준 `ismrmrd` 리더로 다시 열림, ¹H 공명주파수가 필드에 비례.
146
+ - 표준 호환·재현성: 코어 import가 GUI를 끌어오지 않음(headless), 동일 입력 → 동일 출력.
147
+
148
+ ### 알려진 한계 / 근사
149
+ - **신호 시뮬레이션 없음.** 팬텀은 기하·파라미터까지만. parameter→영상은 v0.3.0(Bloch 엔진).
150
+ - **절차적 팬텀은 근사 해부.** 실제 BrainWeb 해부가 필요하면 다운로더로 받아 적재(번들 금지).
151
+ ICBM152 affine은 중심 정렬 근사이며 실제 템플릿에 등록(registration)되지 않음.
152
+ - **7T 조직값은 less-standardized**로 플래그(Rooney 외삽 + Peters). glial/connective/skin은
153
+ 표준 brain-MR relaxometry가 없어 인접 조직값을 차용(`approximate` 플래그).
154
+ - 음향 노이즈·아티팩트·멀티코일·CS는 이후 마일스톤(M3~M5).
155
+
156
+ ### 설치·예제
157
+ ```bash
158
+ pip install blochtwin
159
+ python examples/quickstart.py # 전체 파이프라인 데모
160
+ blochtwin info # 버전·디바이스·상태
161
+ ```
162
+
163
+ ### 인용
164
+ [CITATION.cff](CITATION.cff) 참조. v0.2.0 첫 태그에서 Zenodo DOI 자동 발행 예정.
@@ -0,0 +1,44 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it using the metadata below."
3
+ title: "BlochTwin: a physics-faithful open MRI scanner simulator for synthetic data and teaching"
4
+ type: software
5
+ authors:
6
+ - family-names: "Lee"
7
+ given-names: "Hoonjae"
8
+ alias: "이훈재"
9
+ affiliation: "newmean.ai (Newmean AI)"
10
+ email: "dev@newmean.ai"
11
+ # orcid: "https://orcid.org/0000-0000-0000-0000" # ORCID 발급 후 채울 것
12
+ repository-code: "https://github.com/newmean-ai/blochtwin"
13
+ url: "https://github.com/newmean-ai/blochtwin"
14
+ abstract: >-
15
+ An open, GPU-accelerated, physics-faithful MRI scanner simulator (digital twin)
16
+ for generating realistic synthetic MRI training data and for teaching scanner
17
+ operation (parameter to image and scan-time intuition). Models a high-resolution
18
+ 3D brain phantom with partial-volume effects, 1.5T/3T/7T field strengths,
19
+ viewable RF pulse sequences, gradient-coil acoustic noise tied to gradient
20
+ switching, k-space acquisition and reconstruction (with SENSE/GRAPPA/CS on the
21
+ roadmap).
22
+ keywords:
23
+ - MRI
24
+ - simulation
25
+ - digital twin
26
+ - synthetic data
27
+ - Bloch equations
28
+ - k-space
29
+ - deep learning
30
+ - medical imaging
31
+ - acoustic noise
32
+ license: "Apache-2.0"
33
+ version: "0.3.1"
34
+ date-released: "2026-06-10"
35
+ # 동반 논문(MRM 또는 ISMRM abstract) 출간 후 preferred-citation 블록 추가:
36
+ # preferred-citation:
37
+ # type: article
38
+ # title: "..."
39
+ # authors:
40
+ # - family-names: "Lee"
41
+ # given-names: "Hoonjae"
42
+ # journal: "Magnetic Resonance in Medicine"
43
+ # year: 2026
44
+ # doi: "10.1002/mrm.XXXXX"
@@ -0,0 +1,24 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 Hoonjae Lee (이훈재), newmean.ai
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
18
+
19
+ SPDX-License-Identifier: Apache-2.0
20
+
21
+ NOTE: Before the first public release, replace this file with the FULL verbatim
22
+ text of the Apache License 2.0 (the ~11KB canonical text from the URL above).
23
+ Trademark note: see the NOTICE file. "BlochTwin" is a trademark of newmean.ai
24
+ and is not licensed under Apache-2.0.
blochtwin-0.3.1/NOTICE ADDED
@@ -0,0 +1,11 @@
1
+ BlochTwin
2
+ Copyright 2026 Hoonjae Lee (이훈재), newmean.ai
3
+
4
+ This product includes software developed by Hoonjae Lee / newmean.ai.
5
+
6
+ "BlochTwin" and the project name and logo are trademarks of newmean.ai.
7
+ Use of the source code is governed by the Apache License 2.0 (see LICENSE).
8
+ The Apache-2.0 license does NOT grant trademark rights: forks and derivatives
9
+ may not use the "BlochTwin" name, logo, or "BlochTwin-validated" mark without
10
+ permission. Commercial offerings (hosted generation, validated presets,
11
+ validation reports, enterprise support): dev@newmean.ai
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.5
2
+ Name: blochtwin
3
+ Version: 0.3.1
4
+ Summary: Physics-faithful, GPU-accelerated open-source MRI scanner simulator (digital twin) for synthetic ML training data and scanner-operation teaching.
5
+ Project-URL: Homepage, https://github.com/newmean-ai/blochtwin
6
+ Project-URL: Repository, https://github.com/newmean-ai/blochtwin
7
+ Project-URL: Issues, https://github.com/newmean-ai/blochtwin/issues
8
+ Author-email: Hoonjae Lee <dev@newmean.ai>
9
+ License: Apache License
10
+ Version 2.0, January 2004
11
+ http://www.apache.org/licenses/
12
+
13
+ Copyright 2026 Hoonjae Lee (이훈재), newmean.ai
14
+
15
+ Licensed under the Apache License, Version 2.0 (the "License");
16
+ you may not use this file except in compliance with the License.
17
+ You may obtain a copy of the License at
18
+
19
+ http://www.apache.org/licenses/LICENSE-2.0
20
+
21
+ Unless required by applicable law or agreed to in writing, software
22
+ distributed under the License is distributed on an "AS IS" BASIS,
23
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
+ See the License for the specific language governing permissions and
25
+ limitations under the License.
26
+
27
+ SPDX-License-Identifier: Apache-2.0
28
+
29
+ NOTE: Before the first public release, replace this file with the FULL verbatim
30
+ text of the Apache License 2.0 (the ~11KB canonical text from the URL above).
31
+ Trademark note: see the NOTICE file. "BlochTwin" is a trademark of newmean.ai
32
+ and is not licensed under Apache-2.0.
33
+ License-File: LICENSE
34
+ License-File: NOTICE
35
+ Keywords: Bloch,ISMRMRD,MRI,Pulseq,digital-twin,k-space,medical-imaging,phantom,simulation,synthetic-data
36
+ Classifier: Development Status :: 3 - Alpha
37
+ Classifier: Intended Audience :: Science/Research
38
+ Classifier: License :: OSI Approved :: Apache Software License
39
+ Classifier: Programming Language :: Python :: 3
40
+ Classifier: Programming Language :: Python :: 3.10
41
+ Classifier: Programming Language :: Python :: 3.11
42
+ Classifier: Programming Language :: Python :: 3.12
43
+ Classifier: Programming Language :: Python :: 3.13
44
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
45
+ Classifier: Topic :: Scientific/Engineering :: Physics
46
+ Requires-Python: <3.14,>=3.10
47
+ Requires-Dist: h5py>=3.8
48
+ Requires-Dist: ismrmrd>=1.14
49
+ Requires-Dist: nibabel>=5.0
50
+ Requires-Dist: numpy>=1.24
51
+ Requires-Dist: pypulseq>=1.5
52
+ Requires-Dist: scipy>=1.10
53
+ Requires-Dist: torch>=2.2
54
+ Provides-Extra: all
55
+ Requires-Dist: monai>=1.3; extra == 'all'
56
+ Requires-Dist: napari>=0.4.18; extra == 'all'
57
+ Requires-Dist: pytest-cov>=4.1; extra == 'all'
58
+ Requires-Dist: pytest>=7.4; extra == 'all'
59
+ Requires-Dist: ruff>=0.4; extra == 'all'
60
+ Requires-Dist: streamlit>=1.30; extra == 'all'
61
+ Provides-Extra: app
62
+ Requires-Dist: streamlit>=1.30; extra == 'app'
63
+ Provides-Extra: cuda
64
+ Requires-Dist: cupy-cuda12x>=12.0; extra == 'cuda'
65
+ Provides-Extra: dev
66
+ Requires-Dist: pytest-cov>=4.1; extra == 'dev'
67
+ Requires-Dist: pytest>=7.4; extra == 'dev'
68
+ Requires-Dist: ruff>=0.4; extra == 'dev'
69
+ Provides-Extra: ml
70
+ Requires-Dist: monai>=1.3; extra == 'ml'
71
+ Provides-Extra: viz
72
+ Requires-Dist: napari>=0.4.18; extra == 'viz'
73
+ Description-Content-Type: text/markdown
74
+
75
+ # BlochTwin
76
+
77
+ **A physics-faithful, open-source MRI scanner simulator (digital twin)** for generating
78
+ synthetic MRI training data with perfect ground truth and for learning how scan parameters
79
+ shape the image, the scan time and the artifacts.
80
+
81
+ [![PyPI](https://img.shields.io/pypi/v/blochtwin.svg)](https://pypi.org/project/blochtwin/)
82
+ [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
83
+ ![Python](https://img.shields.io/badge/python-3.10%E2%80%933.13-blue.svg)
84
+
85
+ > **Status: alpha (v0.3).** The core loop works end to end: tissue phantom → Bloch
86
+ > simulation → complex k-space → reconstructed image. Multi-coil acquisition, artifacts and
87
+ > gradient acoustic noise are on the roadmap below.
88
+
89
+ ## Why
90
+
91
+ MRI deep-learning work needs paired data that real scanners cannot provide. That means
92
+ fully sampled complex k-space, noise-free references, voxel-wise tissue maps and exact
93
+ sequence parameters. Physics simulators (JEMRIS, MRiLab, KomaMRI) produce faithful signals,
94
+ but they are not built as ML data pipelines. ML toolkits (TorchIO, MONAI) are easy to use,
95
+ but they fake k-space as the FFT of a magnitude image. BlochTwin aims at the gap between
96
+ them: real acquisition physics, packaged as a headless Python/PyTorch library.
97
+
98
+ - **Contrast comes from physics, not lookup tables.** Each tissue's signal is computed by an
99
+ operator-splitting Bloch engine. T1, T2 and T2\* weighting follow from TR/TE/TI/flip and
100
+ from the refocusing structure of the sequence.
101
+ - **Every tissue parameter is cited.** Tables for T1, T2, T2\*, PD and χ at 1.5, 3 and 7 T
102
+ carry their literature sources (`blochtwin references`). Less-standardized values, such as
103
+ 7 T extrapolations, are flagged.
104
+ - **Differentiable.** The engine is written in PyTorch, so signals keep their autograd graph
105
+ for diff-MRI experiments.
106
+ - **Headless by design.** The core never imports a GUI, so it runs on clusters. Viewers are
107
+ optional.
108
+
109
+ ## Install
110
+
111
+ ```bash
112
+ pip install blochtwin # Python 3.10–3.13, CPU/CUDA, Apple MPS for convenience
113
+ pip install 'blochtwin[viz]' # optional napari 3D inspector (add a Qt backend)
114
+ ```
115
+
116
+ ## Quick start
117
+
118
+ ```python
119
+ import blochtwin as bt
120
+
121
+ phantom = bt.build_brain_phantom(voxel_mm=2.0) # built-in procedural head (incl. air sinuses)
122
+
123
+ # T2-weighted spin echo: CSF bright
124
+ se = bt.simulate(phantom, bt.SpinEcho(matrix=(128, 128), tr_ms=3000, te_ms=100), field_t=3.0)
125
+ print(se.magnitude.shape, se.scan_time_s) # (128, 128) 384.0
126
+
127
+ # T1-weighted spoiled gradient echo: same phantom, different physics, WM bright
128
+ gre = bt.simulate(phantom, bt.GradientEcho(tr_ms=15, te_ms=4, flip_deg=25), field_t=3.0)
129
+
130
+ # FLAIR: inversion recovery that nulls CSF (TI chosen from CSF T1 at 3 T)
131
+ flair = bt.simulate(phantom, bt.FLAIR(), field_t=3.0)
132
+
133
+ kspace, image = gre.kspace, gre.image # complex k-space + reconstruction
134
+ ```
135
+
136
+ The same from the command line:
137
+
138
+ ```bash
139
+ blochtwin simulate --seq se --te 90 # image + k-space + scan time
140
+ blochtwin simulate --seq flair
141
+ blochtwin tables --field 7.0 # cited tissue parameters at 7 T
142
+ blochtwin info
143
+ ```
144
+
145
+ Real anatomy can be loaded from sources you download yourself. Their data is never bundled
146
+ because it is under third-party licenses:
147
+
148
+ ```python
149
+ bt.list_phantom_sources() # sources + licenses
150
+ bt.load_phantom("brainweb", directory="brainweb/") # BrainWeb fuzzy tissue maps
151
+ bt.load_phantom("nyhead", path="nyhead_seg.nii") # New York Head (scalp/skull/air)
152
+ ```
153
+
154
+ ## What works today (v0.3)
155
+
156
+ | Area | Status |
157
+ |---|---|
158
+ | Bloch engine | Operator splitting (rotation ∘ relaxation), differentiable; T2\* via reversible/irreversible split (analytic) or an explicit isochromat ensemble |
159
+ | Sequences | Spin echo, spoiled gradient echo, inversion recovery, FLAIR; apodized-sinc RF with slice rephasing; Pulseq `.seq` export |
160
+ | Phantoms | Fuzzy tissue-fraction model (partial volume built in); procedural head; BrainWeb and New York Head loaders |
161
+ | Physics tables | 1.5 / 3 / 7 T, field-dependent T1 (Rooney power law), cited sources |
162
+ | k-space & recon | Cartesian encoding with matrix crop (Gibbs and resolution emerge naturally), complex Gaussian noise (→ Rician), iFFT recon, deterministic scan time |
163
+ | I/O | Pulseq read/write, ISMRMRD header/skeleton output (full raw export comes with the dataset generator), NIfTI |
164
+
165
+ ### Validation
166
+
167
+ - Steady-state GRE and SE signals match closed-form solutions to machine precision. IR
168
+ matches too, except right at the null point.
169
+ - Single-voxel cross-check against **KomaMRI.jl 0.10.4** (SE, IR, flip sweeps over WM, GM and
170
+ CSF): **0.0023 % mean absolute difference** (worst 0.011 %). Reproduce with
171
+ `benchmarks/compare.py`.
172
+
173
+ ## Roadmap
174
+
175
+ 1. **Artifacts, field strength and acoustics.** Sampling patterns, motion, chemical shift,
176
+ susceptibility, EPI ghosts, and **gradient acoustic noise**, which no open simulator
177
+ models today.
178
+ 2. **Multi-coil.** Coil sensitivities, SENSE and GRAPPA.
179
+ 3. **Compressed sensing.**
180
+ 4. **Dataset generator.** Paired, fastMRI-compatible tuples with domain randomization, plus
181
+ an interactive teaching UI.
182
+ 5. **v1.0.** Validation against real data (fastMRI) and a companion paper.
183
+
184
+ ## How to cite
185
+
186
+ If you use BlochTwin in academic work, please cite it (see [CITATION.cff](CITATION.cff); a
187
+ Zenodo DOI will be added with the first tagged release). Citation is a community norm we ask
188
+ you to honor, not a license restriction.
189
+
190
+ ## License
191
+
192
+ Apache License 2.0. You are free to use, modify and distribute BlochTwin, including
193
+ commercially. "BlochTwin" and its logo are trademarks of newmean.ai. Forks may use the code
194
+ but not the name or logo (see [NOTICE](NOTICE)).
195
+
196
+ Questions and physics-fidelity reports are welcome on
197
+ [GitHub Issues](https://github.com/newmean-ai/blochtwin/issues) or at dev@newmean.ai.
@@ -0,0 +1,123 @@
1
+ # BlochTwin
2
+
3
+ **A physics-faithful, open-source MRI scanner simulator (digital twin)** for generating
4
+ synthetic MRI training data with perfect ground truth and for learning how scan parameters
5
+ shape the image, the scan time and the artifacts.
6
+
7
+ [![PyPI](https://img.shields.io/pypi/v/blochtwin.svg)](https://pypi.org/project/blochtwin/)
8
+ [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
9
+ ![Python](https://img.shields.io/badge/python-3.10%E2%80%933.13-blue.svg)
10
+
11
+ > **Status: alpha (v0.3).** The core loop works end to end: tissue phantom → Bloch
12
+ > simulation → complex k-space → reconstructed image. Multi-coil acquisition, artifacts and
13
+ > gradient acoustic noise are on the roadmap below.
14
+
15
+ ## Why
16
+
17
+ MRI deep-learning work needs paired data that real scanners cannot provide. That means
18
+ fully sampled complex k-space, noise-free references, voxel-wise tissue maps and exact
19
+ sequence parameters. Physics simulators (JEMRIS, MRiLab, KomaMRI) produce faithful signals,
20
+ but they are not built as ML data pipelines. ML toolkits (TorchIO, MONAI) are easy to use,
21
+ but they fake k-space as the FFT of a magnitude image. BlochTwin aims at the gap between
22
+ them: real acquisition physics, packaged as a headless Python/PyTorch library.
23
+
24
+ - **Contrast comes from physics, not lookup tables.** Each tissue's signal is computed by an
25
+ operator-splitting Bloch engine. T1, T2 and T2\* weighting follow from TR/TE/TI/flip and
26
+ from the refocusing structure of the sequence.
27
+ - **Every tissue parameter is cited.** Tables for T1, T2, T2\*, PD and χ at 1.5, 3 and 7 T
28
+ carry their literature sources (`blochtwin references`). Less-standardized values, such as
29
+ 7 T extrapolations, are flagged.
30
+ - **Differentiable.** The engine is written in PyTorch, so signals keep their autograd graph
31
+ for diff-MRI experiments.
32
+ - **Headless by design.** The core never imports a GUI, so it runs on clusters. Viewers are
33
+ optional.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ pip install blochtwin # Python 3.10–3.13, CPU/CUDA, Apple MPS for convenience
39
+ pip install 'blochtwin[viz]' # optional napari 3D inspector (add a Qt backend)
40
+ ```
41
+
42
+ ## Quick start
43
+
44
+ ```python
45
+ import blochtwin as bt
46
+
47
+ phantom = bt.build_brain_phantom(voxel_mm=2.0) # built-in procedural head (incl. air sinuses)
48
+
49
+ # T2-weighted spin echo: CSF bright
50
+ se = bt.simulate(phantom, bt.SpinEcho(matrix=(128, 128), tr_ms=3000, te_ms=100), field_t=3.0)
51
+ print(se.magnitude.shape, se.scan_time_s) # (128, 128) 384.0
52
+
53
+ # T1-weighted spoiled gradient echo: same phantom, different physics, WM bright
54
+ gre = bt.simulate(phantom, bt.GradientEcho(tr_ms=15, te_ms=4, flip_deg=25), field_t=3.0)
55
+
56
+ # FLAIR: inversion recovery that nulls CSF (TI chosen from CSF T1 at 3 T)
57
+ flair = bt.simulate(phantom, bt.FLAIR(), field_t=3.0)
58
+
59
+ kspace, image = gre.kspace, gre.image # complex k-space + reconstruction
60
+ ```
61
+
62
+ The same from the command line:
63
+
64
+ ```bash
65
+ blochtwin simulate --seq se --te 90 # image + k-space + scan time
66
+ blochtwin simulate --seq flair
67
+ blochtwin tables --field 7.0 # cited tissue parameters at 7 T
68
+ blochtwin info
69
+ ```
70
+
71
+ Real anatomy can be loaded from sources you download yourself. Their data is never bundled
72
+ because it is under third-party licenses:
73
+
74
+ ```python
75
+ bt.list_phantom_sources() # sources + licenses
76
+ bt.load_phantom("brainweb", directory="brainweb/") # BrainWeb fuzzy tissue maps
77
+ bt.load_phantom("nyhead", path="nyhead_seg.nii") # New York Head (scalp/skull/air)
78
+ ```
79
+
80
+ ## What works today (v0.3)
81
+
82
+ | Area | Status |
83
+ |---|---|
84
+ | Bloch engine | Operator splitting (rotation ∘ relaxation), differentiable; T2\* via reversible/irreversible split (analytic) or an explicit isochromat ensemble |
85
+ | Sequences | Spin echo, spoiled gradient echo, inversion recovery, FLAIR; apodized-sinc RF with slice rephasing; Pulseq `.seq` export |
86
+ | Phantoms | Fuzzy tissue-fraction model (partial volume built in); procedural head; BrainWeb and New York Head loaders |
87
+ | Physics tables | 1.5 / 3 / 7 T, field-dependent T1 (Rooney power law), cited sources |
88
+ | k-space & recon | Cartesian encoding with matrix crop (Gibbs and resolution emerge naturally), complex Gaussian noise (→ Rician), iFFT recon, deterministic scan time |
89
+ | I/O | Pulseq read/write, ISMRMRD header/skeleton output (full raw export comes with the dataset generator), NIfTI |
90
+
91
+ ### Validation
92
+
93
+ - Steady-state GRE and SE signals match closed-form solutions to machine precision. IR
94
+ matches too, except right at the null point.
95
+ - Single-voxel cross-check against **KomaMRI.jl 0.10.4** (SE, IR, flip sweeps over WM, GM and
96
+ CSF): **0.0023 % mean absolute difference** (worst 0.011 %). Reproduce with
97
+ `benchmarks/compare.py`.
98
+
99
+ ## Roadmap
100
+
101
+ 1. **Artifacts, field strength and acoustics.** Sampling patterns, motion, chemical shift,
102
+ susceptibility, EPI ghosts, and **gradient acoustic noise**, which no open simulator
103
+ models today.
104
+ 2. **Multi-coil.** Coil sensitivities, SENSE and GRAPPA.
105
+ 3. **Compressed sensing.**
106
+ 4. **Dataset generator.** Paired, fastMRI-compatible tuples with domain randomization, plus
107
+ an interactive teaching UI.
108
+ 5. **v1.0.** Validation against real data (fastMRI) and a companion paper.
109
+
110
+ ## How to cite
111
+
112
+ If you use BlochTwin in academic work, please cite it (see [CITATION.cff](CITATION.cff); a
113
+ Zenodo DOI will be added with the first tagged release). Citation is a community norm we ask
114
+ you to honor, not a license restriction.
115
+
116
+ ## License
117
+
118
+ Apache License 2.0. You are free to use, modify and distribute BlochTwin, including
119
+ commercially. "BlochTwin" and its logo are trademarks of newmean.ai. Forks may use the code
120
+ but not the name or logo (see [NOTICE](NOTICE)).
121
+
122
+ Questions and physics-fidelity reports are welcome on
123
+ [GitHub Issues](https://github.com/newmean-ai/blochtwin/issues) or at dev@newmean.ai.