blochsimulator 1.0.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.
- blochsimulator-1.0.0/MANIFEST.in +6 -0
- blochsimulator-1.0.0/PKG-INFO +344 -0
- blochsimulator-1.0.0/README.md +318 -0
- blochsimulator-1.0.0/pyproject.toml +36 -0
- blochsimulator-1.0.0/requirements.txt +25 -0
- blochsimulator-1.0.0/rfpulses/.DS_Store +0 -0
- blochsimulator-1.0.0/rfpulses/AHP_5ms_Hsn.dat +1024 -0
- blochsimulator-1.0.0/rfpulses/SLR_sharpness_5.txt +1 -0
- blochsimulator-1.0.0/rfpulses/bruker/13C_Ultimate_SPSP_Pulse_QuEMRT.exc +2502 -0
- blochsimulator-1.0.0/setup.cfg +4 -0
- blochsimulator-1.0.0/setup.py +81 -0
- blochsimulator-1.0.0/src/bloch_simulator/__init__.py +11 -0
- blochsimulator-1.0.0/src/bloch_simulator/bloch_core.h +98 -0
- blochsimulator-1.0.0/src/bloch_simulator/bloch_core_modified.c +794 -0
- blochsimulator-1.0.0/src/bloch_simulator/bloch_wrapper.c +24462 -0
- blochsimulator-1.0.0/src/bloch_simulator/bloch_wrapper.pyx +708 -0
- blochsimulator-1.0.0/src/bloch_simulator/gui.py +8549 -0
- blochsimulator-1.0.0/src/bloch_simulator/gui_phantom_integration.py +116 -0
- blochsimulator-1.0.0/src/bloch_simulator/kspace.py +1173 -0
- blochsimulator-1.0.0/src/bloch_simulator/kspace_widget.py +1309 -0
- blochsimulator-1.0.0/src/bloch_simulator/notebook_exporter.py +677 -0
- blochsimulator-1.0.0/src/bloch_simulator/phantom.py +1036 -0
- blochsimulator-1.0.0/src/bloch_simulator/phantom_widget.py +980 -0
- blochsimulator-1.0.0/src/bloch_simulator/pulse_loader.py +578 -0
- blochsimulator-1.0.0/src/bloch_simulator/simulator.py +1531 -0
- blochsimulator-1.0.0/src/bloch_simulator/spectral_phantom.py +932 -0
- blochsimulator-1.0.0/src/bloch_simulator/visualization.py +862 -0
- blochsimulator-1.0.0/src/blochsimulator.egg-info/PKG-INFO +344 -0
- blochsimulator-1.0.0/src/blochsimulator.egg-info/SOURCES.txt +37 -0
- blochsimulator-1.0.0/src/blochsimulator.egg-info/dependency_links.txt +1 -0
- blochsimulator-1.0.0/src/blochsimulator.egg-info/entry_points.txt +2 -0
- blochsimulator-1.0.0/src/blochsimulator.egg-info/not-zip-safe +1 -0
- blochsimulator-1.0.0/src/blochsimulator.egg-info/requires.txt +18 -0
- blochsimulator-1.0.0/src/blochsimulator.egg-info/top_level.txt +1 -0
- blochsimulator-1.0.0/tests/test_export.py +131 -0
- blochsimulator-1.0.0/tests/test_export_simple.py +57 -0
- blochsimulator-1.0.0/tests/test_input_shapes.py +53 -0
- blochsimulator-1.0.0/tests/test_notebook_export.py +290 -0
- blochsimulator-1.0.0/tests/test_visualization_export.py +309 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: blochsimulator
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: High-performance Bloch equation simulator for MRI
|
|
5
|
+
Author: Luca Nagel
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/yourusername/bloch_simulator
|
|
8
|
+
Requires-Python: >=3.8
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: numpy>=1.20.0
|
|
11
|
+
Requires-Dist: scipy>=1.7.0
|
|
12
|
+
Requires-Dist: matplotlib>=3.3.0
|
|
13
|
+
Requires-Dist: cython>=0.29.0
|
|
14
|
+
Requires-Dist: PyQt5>=5.15.0
|
|
15
|
+
Requires-Dist: pyqtgraph>=0.12.0
|
|
16
|
+
Requires-Dist: PyOpenGL>=3.1.0
|
|
17
|
+
Requires-Dist: imageio>=2.34.0
|
|
18
|
+
Requires-Dist: imageio-ffmpeg>=0.4.9
|
|
19
|
+
Requires-Dist: h5py>=3.0.0
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest; extra == "dev"
|
|
22
|
+
Requires-Dist: black; extra == "dev"
|
|
23
|
+
Requires-Dist: flake8; extra == "dev"
|
|
24
|
+
Provides-Extra: notebook
|
|
25
|
+
Requires-Dist: jupyterlab; extra == "notebook"
|
|
26
|
+
|
|
27
|
+
# Bloch Equation Simulator for Python
|
|
28
|
+
|
|
29
|
+
A high-performance Python implementation of the Bloch equation solver originally developed by Brian Hargreaves at Stanford University. This package provides a fast C-based core with Python bindings, parallel processing support, and an interactive GUI for MRI pulse sequence simulation.
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- **High Performance**: C implementation with Cython bindings maintains original speed
|
|
34
|
+
- **Parallel Processing**: OpenMP support for multi-core acceleration
|
|
35
|
+
- **Interactive GUI**: Real-time visualization and parameter adjustment
|
|
36
|
+
- **Flexible API**: Easy-to-use Python interface for scripting
|
|
37
|
+
- **Comprehensive**: Supports arbitrary RF pulses, gradient waveforms, and tissue parameters
|
|
38
|
+
- **Visualization**: 3D magnetization vectors, time evolution plots, frequency spectra, and **animation export**
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
### Prerequisites
|
|
43
|
+
|
|
44
|
+
1. **Python 3.7+**
|
|
45
|
+
2. **C Compiler**:
|
|
46
|
+
- Linux: `gcc` (usually pre-installed)
|
|
47
|
+
- macOS: Xcode Command Line Tools (`xcode-select --install`)
|
|
48
|
+
- Windows: Visual Studio Build Tools
|
|
49
|
+
3. **OpenMP** (optional but recommended):
|
|
50
|
+
- Linux: Included with gcc
|
|
51
|
+
- macOS: `brew install libomp`
|
|
52
|
+
- Windows: Included with Visual Studio
|
|
53
|
+
|
|
54
|
+
### Quick Setup
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Clone or download the repository
|
|
58
|
+
cd bloch_simulator
|
|
59
|
+
|
|
60
|
+
# Install dependencies
|
|
61
|
+
pip install -r requirements.txt
|
|
62
|
+
|
|
63
|
+
# Build the extension
|
|
64
|
+
python build.py
|
|
65
|
+
|
|
66
|
+
# Or manually:
|
|
67
|
+
python setup.py build_ext --inplace
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Verification
|
|
71
|
+
|
|
72
|
+
Test the installation:
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from bloch_simulator import BlochSimulator, TissueParameters
|
|
76
|
+
|
|
77
|
+
sim = BlochSimulator()
|
|
78
|
+
tissue = TissueParameters.gray_matter(3.0)
|
|
79
|
+
print(f"T1: {tissue.t1:.3f}s, T2: {tissue.t2:.3f}s")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Usage
|
|
83
|
+
|
|
84
|
+
### 1. GUI Application
|
|
85
|
+
|
|
86
|
+
Launch the interactive GUI:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python bloch_gui.py
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Features:
|
|
93
|
+
- Design RF pulses (rectangular, sinc, Gaussian)
|
|
94
|
+
- Configure tissue parameters (T1, T2, proton density)
|
|
95
|
+
- Select pulse sequences (spin echo, gradient echo, etc.)
|
|
96
|
+
- Real-time 3D magnetization visualization
|
|
97
|
+
- Signal analysis and frequency spectra
|
|
98
|
+
|
|
99
|
+
### 2. Python API
|
|
100
|
+
|
|
101
|
+
#### Basic Simulation
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import numpy as np
|
|
105
|
+
from bloch_simulator import BlochSimulator, TissueParameters
|
|
106
|
+
|
|
107
|
+
# Create simulator
|
|
108
|
+
sim = BlochSimulator(use_parallel=True, num_threads=4)
|
|
109
|
+
|
|
110
|
+
# Define tissue parameters
|
|
111
|
+
tissue = TissueParameters(
|
|
112
|
+
name="Gray Matter",
|
|
113
|
+
t1=1.33, # seconds
|
|
114
|
+
t2=0.083 # seconds
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Create a simple 90-degree pulse
|
|
118
|
+
ntime = 100
|
|
119
|
+
dt = 1e-5 # 10 microseconds
|
|
120
|
+
time = np.arange(ntime) * dt
|
|
121
|
+
|
|
122
|
+
b1 = np.zeros(ntime, dtype=complex)
|
|
123
|
+
b1[0] = 0.0235 # 90-degree hard pulse
|
|
124
|
+
|
|
125
|
+
gradients = np.zeros((ntime, 3)) # No gradients
|
|
126
|
+
|
|
127
|
+
# Run simulation
|
|
128
|
+
result = sim.simulate(
|
|
129
|
+
sequence=(b1, gradients, time),
|
|
130
|
+
tissue=tissue,
|
|
131
|
+
mode=2 # Time-resolved output
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Plot results
|
|
135
|
+
sim.plot_magnetization()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Spin Echo Sequence
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from bloch_simulator import BlochSimulator, SpinEcho, TissueParameters
|
|
142
|
+
|
|
143
|
+
sim = BlochSimulator()
|
|
144
|
+
|
|
145
|
+
# Create spin echo sequence
|
|
146
|
+
sequence = SpinEcho(te=20e-3, tr=500e-3) # 20ms TE, 500ms TR
|
|
147
|
+
|
|
148
|
+
# Simulate white matter
|
|
149
|
+
tissue = TissueParameters.white_matter(3.0)
|
|
150
|
+
|
|
151
|
+
# Run simulation with multiple frequencies (T2* effects)
|
|
152
|
+
frequencies = np.linspace(-50, 50, 11) # Hz
|
|
153
|
+
result = sim.simulate(sequence, tissue, frequencies=frequencies)
|
|
154
|
+
|
|
155
|
+
# Access magnetization components
|
|
156
|
+
mx, my, mz = result['mx'], result['my'], result['mz']
|
|
157
|
+
signal = result['signal']
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### Custom Pulse Design
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from bloch_simulator import design_rf_pulse
|
|
164
|
+
|
|
165
|
+
# Design a sinc pulse
|
|
166
|
+
b1, time = design_rf_pulse(
|
|
167
|
+
pulse_type='sinc',
|
|
168
|
+
duration=2e-3, # 2 ms
|
|
169
|
+
flip_angle=180, # degrees
|
|
170
|
+
time_bw_product=4, # Time-bandwidth product
|
|
171
|
+
npoints=200
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
# Apply phase
|
|
175
|
+
phase = np.pi/4 # 45 degrees
|
|
176
|
+
b1_phased = b1 * np.exp(1j * phase)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### Parallel Simulation
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
# Simulate multiple positions and frequencies in parallel
|
|
183
|
+
positions = np.random.randn(100, 3) * 0.01 # Random positions in 1cm cube
|
|
184
|
+
frequencies = np.linspace(-200, 200, 41) # 41 frequencies
|
|
185
|
+
|
|
186
|
+
result = sim.simulate(
|
|
187
|
+
sequence=sequence,
|
|
188
|
+
tissue=tissue,
|
|
189
|
+
positions=positions,
|
|
190
|
+
frequencies=frequencies,
|
|
191
|
+
mode=0 # Endpoint only (faster)
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
# Result shape: (100 positions, 41 frequencies)
|
|
195
|
+
print(f"Signal shape: {result['signal'].shape}")
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 3. Sequence Library
|
|
199
|
+
|
|
200
|
+
Pre-defined sequences are available:
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from bloch_simulator import SpinEcho, GradientEcho
|
|
204
|
+
|
|
205
|
+
# Spin Echo
|
|
206
|
+
se = SpinEcho(te=30e-3, tr=1.0)
|
|
207
|
+
|
|
208
|
+
# Gradient Echo
|
|
209
|
+
gre = GradientEcho(te=5e-3, tr=10e-3, flip_angle=30)
|
|
210
|
+
|
|
211
|
+
# Compile to waveforms
|
|
212
|
+
b1, gradients, time = se.compile(dt=1e-6)
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 4. Tissue Parameter Library
|
|
216
|
+
|
|
217
|
+
Common tissues at different field strengths:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
from bloch_simulator import TissueParameters
|
|
221
|
+
|
|
222
|
+
# 3T parameters
|
|
223
|
+
gm = TissueParameters.gray_matter(3.0)
|
|
224
|
+
wm = TissueParameters.white_matter(3.0)
|
|
225
|
+
csf = TissueParameters.csf(3.0)
|
|
226
|
+
|
|
227
|
+
# 7T parameters
|
|
228
|
+
gm_7t = TissueParameters.gray_matter(7.0)
|
|
229
|
+
|
|
230
|
+
# Custom tissue
|
|
231
|
+
liver = TissueParameters(
|
|
232
|
+
name="Liver",
|
|
233
|
+
t1=0.812,
|
|
234
|
+
t2=0.042,
|
|
235
|
+
t2_star=0.028,
|
|
236
|
+
density=0.9
|
|
237
|
+
)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Desktop app build (PyInstaller)
|
|
241
|
+
|
|
242
|
+
One build per OS is required (macOS build won’t run on Windows/Linux).
|
|
243
|
+
|
|
244
|
+
### Prereqs
|
|
245
|
+
- macOS: Xcode CLT; `brew install libomp`.
|
|
246
|
+
- Windows: Python 3.8+ and MSVC Build Tools (for C extension).
|
|
247
|
+
- Linux: gcc/g++; ensure `libgomp` available.
|
|
248
|
+
|
|
249
|
+
### Quick build (any OS)
|
|
250
|
+
```bash
|
|
251
|
+
python -m pip install -r requirements.txt
|
|
252
|
+
python -m pip install pyinstaller
|
|
253
|
+
python setup.py build_ext --inplace
|
|
254
|
+
PYINSTALLER_CONFIG_DIR=.pyinstaller pyinstaller bloch_gui.spec --noconfirm
|
|
255
|
+
```
|
|
256
|
+
Artifact: `dist/BlochSimulator` (single binary; `.exe` on Windows).
|
|
257
|
+
|
|
258
|
+
### One-liner helper
|
|
259
|
+
```bash
|
|
260
|
+
./scripts/build_pyinstaller.sh # creates a venv, installs deps, builds, packages
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Run the packaged app
|
|
264
|
+
- macOS/Linux: `./dist/BlochSimulator`
|
|
265
|
+
- Windows: `dist\\BlochSimulator.exe`
|
|
266
|
+
|
|
267
|
+
### Runtime data/exports
|
|
268
|
+
- `rfpulses/` is bundled automatically.
|
|
269
|
+
- Exports default to per-user data dirs:
|
|
270
|
+
- macOS: `~/Library/Application Support/BlochSimulator/exports`
|
|
271
|
+
- Windows: `%APPDATA%\\BlochSimulator\\exports`
|
|
272
|
+
- Linux: `~/.local/share/BlochSimulator/exports`
|
|
273
|
+
- Override with `BLOCH_APP_DIR` or `BLOCH_EXPORT_DIR` if you need a custom location.
|
|
274
|
+
|
|
275
|
+
## Theory
|
|
276
|
+
|
|
277
|
+
The simulator solves the Bloch equations:
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
dM/dt = γ(M × B) - [Mx/T2, My/T2, (Mz-M0)/T1]
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Using:
|
|
284
|
+
- Rotation matrices for RF and gradient effects
|
|
285
|
+
- Exponential decay for relaxation
|
|
286
|
+
- Cayley-Klein parameters for efficient rotation calculation
|
|
287
|
+
|
|
288
|
+
## Troubleshooting
|
|
289
|
+
|
|
290
|
+
### Build Issues
|
|
291
|
+
|
|
292
|
+
1. **Missing compiler**: Install gcc (Linux), Xcode (macOS), or Visual Studio (Windows)
|
|
293
|
+
2. **OpenMP not found**: The code will still work but without parallelization
|
|
294
|
+
3. **Import error**: Ensure the .so/.pyd file is in the same directory
|
|
295
|
+
|
|
296
|
+
## Contributing
|
|
297
|
+
|
|
298
|
+
Contributions are welcome! Please:
|
|
299
|
+
1. Fork the repository
|
|
300
|
+
2. Create a feature branch
|
|
301
|
+
3. Add tests for new features
|
|
302
|
+
4. Submit a pull request
|
|
303
|
+
|
|
304
|
+
## Citation
|
|
305
|
+
|
|
306
|
+
If you use this simulator in your research, please cite:
|
|
307
|
+
|
|
308
|
+
```bibtex
|
|
309
|
+
@software{bloch_simulator_python,
|
|
310
|
+
title={Python Bloch Equation Simulator GUI and API},
|
|
311
|
+
author={Luca Nagel},
|
|
312
|
+
year={2025},
|
|
313
|
+
url={https://github.com/LucaNagel/bloch_sim_gui}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Acknowledgments
|
|
318
|
+
|
|
319
|
+
This project is based on [code](http://mrsrl.stanford.edu/~brian/blochsim/) originally developed by Brian Hargreaves at Stanford University. Currently (11/2025) it is unfortunately not available. A python adaption of this code can be found [here](https://github.com/ZhengguoTan/BlochSim).
|
|
320
|
+
|
|
321
|
+
- Original Bloch simulator by Brian Hargreaves, Stanford University
|
|
322
|
+
- NumPy and SciPy communities
|
|
323
|
+
- PyQt/PySide developers
|
|
324
|
+
- OpenMP project
|
|
325
|
+
- Built partially with [codex](https://openai.com/codex/), [claude code](https://claude.ai/) and [gemini cli](https://github.com/google-gemini/gemini-cli)
|
|
326
|
+
|
|
327
|
+
## Contact
|
|
328
|
+
|
|
329
|
+
Luca Nagel
|
|
330
|
+
|
|
331
|
+
## Appendix: File Structure
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
bloch_simulator/
|
|
335
|
+
├── bloch_core_modified.c # C implementation (from original)
|
|
336
|
+
├── bloch_core.h # C header file
|
|
337
|
+
├── bloch_wrapper.pyx # Cython wrapper
|
|
338
|
+
├── setup.py # Build configuration
|
|
339
|
+
├── build.py # Build script
|
|
340
|
+
├── bloch_simulator.py # Python API
|
|
341
|
+
├── bloch_gui.py # GUI application
|
|
342
|
+
├── requirements.txt # Dependencies
|
|
343
|
+
└── README.md # This file
|
|
344
|
+
```
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Bloch Equation Simulator for Python
|
|
2
|
+
|
|
3
|
+
A high-performance Python implementation of the Bloch equation solver originally developed by Brian Hargreaves at Stanford University. This package provides a fast C-based core with Python bindings, parallel processing support, and an interactive GUI for MRI pulse sequence simulation.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **High Performance**: C implementation with Cython bindings maintains original speed
|
|
8
|
+
- **Parallel Processing**: OpenMP support for multi-core acceleration
|
|
9
|
+
- **Interactive GUI**: Real-time visualization and parameter adjustment
|
|
10
|
+
- **Flexible API**: Easy-to-use Python interface for scripting
|
|
11
|
+
- **Comprehensive**: Supports arbitrary RF pulses, gradient waveforms, and tissue parameters
|
|
12
|
+
- **Visualization**: 3D magnetization vectors, time evolution plots, frequency spectra, and **animation export**
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
### Prerequisites
|
|
17
|
+
|
|
18
|
+
1. **Python 3.7+**
|
|
19
|
+
2. **C Compiler**:
|
|
20
|
+
- Linux: `gcc` (usually pre-installed)
|
|
21
|
+
- macOS: Xcode Command Line Tools (`xcode-select --install`)
|
|
22
|
+
- Windows: Visual Studio Build Tools
|
|
23
|
+
3. **OpenMP** (optional but recommended):
|
|
24
|
+
- Linux: Included with gcc
|
|
25
|
+
- macOS: `brew install libomp`
|
|
26
|
+
- Windows: Included with Visual Studio
|
|
27
|
+
|
|
28
|
+
### Quick Setup
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Clone or download the repository
|
|
32
|
+
cd bloch_simulator
|
|
33
|
+
|
|
34
|
+
# Install dependencies
|
|
35
|
+
pip install -r requirements.txt
|
|
36
|
+
|
|
37
|
+
# Build the extension
|
|
38
|
+
python build.py
|
|
39
|
+
|
|
40
|
+
# Or manually:
|
|
41
|
+
python setup.py build_ext --inplace
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Verification
|
|
45
|
+
|
|
46
|
+
Test the installation:
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from bloch_simulator import BlochSimulator, TissueParameters
|
|
50
|
+
|
|
51
|
+
sim = BlochSimulator()
|
|
52
|
+
tissue = TissueParameters.gray_matter(3.0)
|
|
53
|
+
print(f"T1: {tissue.t1:.3f}s, T2: {tissue.t2:.3f}s")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
### 1. GUI Application
|
|
59
|
+
|
|
60
|
+
Launch the interactive GUI:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python bloch_gui.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Features:
|
|
67
|
+
- Design RF pulses (rectangular, sinc, Gaussian)
|
|
68
|
+
- Configure tissue parameters (T1, T2, proton density)
|
|
69
|
+
- Select pulse sequences (spin echo, gradient echo, etc.)
|
|
70
|
+
- Real-time 3D magnetization visualization
|
|
71
|
+
- Signal analysis and frequency spectra
|
|
72
|
+
|
|
73
|
+
### 2. Python API
|
|
74
|
+
|
|
75
|
+
#### Basic Simulation
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
import numpy as np
|
|
79
|
+
from bloch_simulator import BlochSimulator, TissueParameters
|
|
80
|
+
|
|
81
|
+
# Create simulator
|
|
82
|
+
sim = BlochSimulator(use_parallel=True, num_threads=4)
|
|
83
|
+
|
|
84
|
+
# Define tissue parameters
|
|
85
|
+
tissue = TissueParameters(
|
|
86
|
+
name="Gray Matter",
|
|
87
|
+
t1=1.33, # seconds
|
|
88
|
+
t2=0.083 # seconds
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Create a simple 90-degree pulse
|
|
92
|
+
ntime = 100
|
|
93
|
+
dt = 1e-5 # 10 microseconds
|
|
94
|
+
time = np.arange(ntime) * dt
|
|
95
|
+
|
|
96
|
+
b1 = np.zeros(ntime, dtype=complex)
|
|
97
|
+
b1[0] = 0.0235 # 90-degree hard pulse
|
|
98
|
+
|
|
99
|
+
gradients = np.zeros((ntime, 3)) # No gradients
|
|
100
|
+
|
|
101
|
+
# Run simulation
|
|
102
|
+
result = sim.simulate(
|
|
103
|
+
sequence=(b1, gradients, time),
|
|
104
|
+
tissue=tissue,
|
|
105
|
+
mode=2 # Time-resolved output
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Plot results
|
|
109
|
+
sim.plot_magnetization()
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Spin Echo Sequence
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from bloch_simulator import BlochSimulator, SpinEcho, TissueParameters
|
|
116
|
+
|
|
117
|
+
sim = BlochSimulator()
|
|
118
|
+
|
|
119
|
+
# Create spin echo sequence
|
|
120
|
+
sequence = SpinEcho(te=20e-3, tr=500e-3) # 20ms TE, 500ms TR
|
|
121
|
+
|
|
122
|
+
# Simulate white matter
|
|
123
|
+
tissue = TissueParameters.white_matter(3.0)
|
|
124
|
+
|
|
125
|
+
# Run simulation with multiple frequencies (T2* effects)
|
|
126
|
+
frequencies = np.linspace(-50, 50, 11) # Hz
|
|
127
|
+
result = sim.simulate(sequence, tissue, frequencies=frequencies)
|
|
128
|
+
|
|
129
|
+
# Access magnetization components
|
|
130
|
+
mx, my, mz = result['mx'], result['my'], result['mz']
|
|
131
|
+
signal = result['signal']
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Custom Pulse Design
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from bloch_simulator import design_rf_pulse
|
|
138
|
+
|
|
139
|
+
# Design a sinc pulse
|
|
140
|
+
b1, time = design_rf_pulse(
|
|
141
|
+
pulse_type='sinc',
|
|
142
|
+
duration=2e-3, # 2 ms
|
|
143
|
+
flip_angle=180, # degrees
|
|
144
|
+
time_bw_product=4, # Time-bandwidth product
|
|
145
|
+
npoints=200
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Apply phase
|
|
149
|
+
phase = np.pi/4 # 45 degrees
|
|
150
|
+
b1_phased = b1 * np.exp(1j * phase)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### Parallel Simulation
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
# Simulate multiple positions and frequencies in parallel
|
|
157
|
+
positions = np.random.randn(100, 3) * 0.01 # Random positions in 1cm cube
|
|
158
|
+
frequencies = np.linspace(-200, 200, 41) # 41 frequencies
|
|
159
|
+
|
|
160
|
+
result = sim.simulate(
|
|
161
|
+
sequence=sequence,
|
|
162
|
+
tissue=tissue,
|
|
163
|
+
positions=positions,
|
|
164
|
+
frequencies=frequencies,
|
|
165
|
+
mode=0 # Endpoint only (faster)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# Result shape: (100 positions, 41 frequencies)
|
|
169
|
+
print(f"Signal shape: {result['signal'].shape}")
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 3. Sequence Library
|
|
173
|
+
|
|
174
|
+
Pre-defined sequences are available:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from bloch_simulator import SpinEcho, GradientEcho
|
|
178
|
+
|
|
179
|
+
# Spin Echo
|
|
180
|
+
se = SpinEcho(te=30e-3, tr=1.0)
|
|
181
|
+
|
|
182
|
+
# Gradient Echo
|
|
183
|
+
gre = GradientEcho(te=5e-3, tr=10e-3, flip_angle=30)
|
|
184
|
+
|
|
185
|
+
# Compile to waveforms
|
|
186
|
+
b1, gradients, time = se.compile(dt=1e-6)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 4. Tissue Parameter Library
|
|
190
|
+
|
|
191
|
+
Common tissues at different field strengths:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
from bloch_simulator import TissueParameters
|
|
195
|
+
|
|
196
|
+
# 3T parameters
|
|
197
|
+
gm = TissueParameters.gray_matter(3.0)
|
|
198
|
+
wm = TissueParameters.white_matter(3.0)
|
|
199
|
+
csf = TissueParameters.csf(3.0)
|
|
200
|
+
|
|
201
|
+
# 7T parameters
|
|
202
|
+
gm_7t = TissueParameters.gray_matter(7.0)
|
|
203
|
+
|
|
204
|
+
# Custom tissue
|
|
205
|
+
liver = TissueParameters(
|
|
206
|
+
name="Liver",
|
|
207
|
+
t1=0.812,
|
|
208
|
+
t2=0.042,
|
|
209
|
+
t2_star=0.028,
|
|
210
|
+
density=0.9
|
|
211
|
+
)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Desktop app build (PyInstaller)
|
|
215
|
+
|
|
216
|
+
One build per OS is required (macOS build won’t run on Windows/Linux).
|
|
217
|
+
|
|
218
|
+
### Prereqs
|
|
219
|
+
- macOS: Xcode CLT; `brew install libomp`.
|
|
220
|
+
- Windows: Python 3.8+ and MSVC Build Tools (for C extension).
|
|
221
|
+
- Linux: gcc/g++; ensure `libgomp` available.
|
|
222
|
+
|
|
223
|
+
### Quick build (any OS)
|
|
224
|
+
```bash
|
|
225
|
+
python -m pip install -r requirements.txt
|
|
226
|
+
python -m pip install pyinstaller
|
|
227
|
+
python setup.py build_ext --inplace
|
|
228
|
+
PYINSTALLER_CONFIG_DIR=.pyinstaller pyinstaller bloch_gui.spec --noconfirm
|
|
229
|
+
```
|
|
230
|
+
Artifact: `dist/BlochSimulator` (single binary; `.exe` on Windows).
|
|
231
|
+
|
|
232
|
+
### One-liner helper
|
|
233
|
+
```bash
|
|
234
|
+
./scripts/build_pyinstaller.sh # creates a venv, installs deps, builds, packages
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Run the packaged app
|
|
238
|
+
- macOS/Linux: `./dist/BlochSimulator`
|
|
239
|
+
- Windows: `dist\\BlochSimulator.exe`
|
|
240
|
+
|
|
241
|
+
### Runtime data/exports
|
|
242
|
+
- `rfpulses/` is bundled automatically.
|
|
243
|
+
- Exports default to per-user data dirs:
|
|
244
|
+
- macOS: `~/Library/Application Support/BlochSimulator/exports`
|
|
245
|
+
- Windows: `%APPDATA%\\BlochSimulator\\exports`
|
|
246
|
+
- Linux: `~/.local/share/BlochSimulator/exports`
|
|
247
|
+
- Override with `BLOCH_APP_DIR` or `BLOCH_EXPORT_DIR` if you need a custom location.
|
|
248
|
+
|
|
249
|
+
## Theory
|
|
250
|
+
|
|
251
|
+
The simulator solves the Bloch equations:
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
dM/dt = γ(M × B) - [Mx/T2, My/T2, (Mz-M0)/T1]
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Using:
|
|
258
|
+
- Rotation matrices for RF and gradient effects
|
|
259
|
+
- Exponential decay for relaxation
|
|
260
|
+
- Cayley-Klein parameters for efficient rotation calculation
|
|
261
|
+
|
|
262
|
+
## Troubleshooting
|
|
263
|
+
|
|
264
|
+
### Build Issues
|
|
265
|
+
|
|
266
|
+
1. **Missing compiler**: Install gcc (Linux), Xcode (macOS), or Visual Studio (Windows)
|
|
267
|
+
2. **OpenMP not found**: The code will still work but without parallelization
|
|
268
|
+
3. **Import error**: Ensure the .so/.pyd file is in the same directory
|
|
269
|
+
|
|
270
|
+
## Contributing
|
|
271
|
+
|
|
272
|
+
Contributions are welcome! Please:
|
|
273
|
+
1. Fork the repository
|
|
274
|
+
2. Create a feature branch
|
|
275
|
+
3. Add tests for new features
|
|
276
|
+
4. Submit a pull request
|
|
277
|
+
|
|
278
|
+
## Citation
|
|
279
|
+
|
|
280
|
+
If you use this simulator in your research, please cite:
|
|
281
|
+
|
|
282
|
+
```bibtex
|
|
283
|
+
@software{bloch_simulator_python,
|
|
284
|
+
title={Python Bloch Equation Simulator GUI and API},
|
|
285
|
+
author={Luca Nagel},
|
|
286
|
+
year={2025},
|
|
287
|
+
url={https://github.com/LucaNagel/bloch_sim_gui}
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Acknowledgments
|
|
292
|
+
|
|
293
|
+
This project is based on [code](http://mrsrl.stanford.edu/~brian/blochsim/) originally developed by Brian Hargreaves at Stanford University. Currently (11/2025) it is unfortunately not available. A python adaption of this code can be found [here](https://github.com/ZhengguoTan/BlochSim).
|
|
294
|
+
|
|
295
|
+
- Original Bloch simulator by Brian Hargreaves, Stanford University
|
|
296
|
+
- NumPy and SciPy communities
|
|
297
|
+
- PyQt/PySide developers
|
|
298
|
+
- OpenMP project
|
|
299
|
+
- Built partially with [codex](https://openai.com/codex/), [claude code](https://claude.ai/) and [gemini cli](https://github.com/google-gemini/gemini-cli)
|
|
300
|
+
|
|
301
|
+
## Contact
|
|
302
|
+
|
|
303
|
+
Luca Nagel
|
|
304
|
+
|
|
305
|
+
## Appendix: File Structure
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
bloch_simulator/
|
|
309
|
+
├── bloch_core_modified.c # C implementation (from original)
|
|
310
|
+
├── bloch_core.h # C header file
|
|
311
|
+
├── bloch_wrapper.pyx # Cython wrapper
|
|
312
|
+
├── setup.py # Build configuration
|
|
313
|
+
├── build.py # Build script
|
|
314
|
+
├── bloch_simulator.py # Python API
|
|
315
|
+
├── bloch_gui.py # GUI application
|
|
316
|
+
├── requirements.txt # Dependencies
|
|
317
|
+
└── README.md # This file
|
|
318
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=42", "wheel", "Cython>=0.29", "numpy>=1.20"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "blochsimulator"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "High-performance Bloch equation simulator for MRI"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.8"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Luca Nagel"}
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"numpy>=1.20.0",
|
|
17
|
+
"scipy>=1.7.0",
|
|
18
|
+
"matplotlib>=3.3.0",
|
|
19
|
+
"cython>=0.29.0",
|
|
20
|
+
"PyQt5>=5.15.0",
|
|
21
|
+
"pyqtgraph>=0.12.0",
|
|
22
|
+
"PyOpenGL>=3.1.0",
|
|
23
|
+
"imageio>=2.34.0",
|
|
24
|
+
"imageio-ffmpeg>=0.4.9",
|
|
25
|
+
"h5py>=3.0.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = ["pytest", "black", "flake8"]
|
|
30
|
+
notebook = ["jupyterlab"]
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
bloch-gui = "bloch_simulator.gui:main"
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/yourusername/bloch_simulator"
|