toolapi 0.1.0__tar.gz → 0.1.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.
Potentially problematic release.
This version of toolapi might be problematic. Click here for more details.
- {toolapi-0.1.0 → toolapi-0.1.1}/Cargo.lock +41 -23
- {toolapi-0.1.0 → toolapi-0.1.1}/Cargo.toml +1 -1
- {toolapi-0.1.0 → toolapi-0.1.1}/PKG-INFO +1 -1
- toolapi-0.1.1/test/demo_notebook.ipynb +324 -0
- toolapi-0.1.1/test/demo_notebook_minimal.ipynb +127 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/.github/workflows/pypi_publish.yml +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/.gitignore +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/CLAUDE.md +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/README.md +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/pyproject.toml +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/src/lib.rs +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/src/toolapi/__init__.py +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/src/toolapi/_core.pyi +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/src/toolapi/value.py +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/test/load_phantom.py +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/test/pyproject.toml +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/test/test_toolapi.py +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/test/util.py +0 -0
- {toolapi-0.1.0 → toolapi-0.1.1}/uv.lock +0 -0
|
@@ -86,15 +86,15 @@ dependencies = [
|
|
|
86
86
|
|
|
87
87
|
[[package]]
|
|
88
88
|
name = "bytes"
|
|
89
|
-
version = "1.11.
|
|
89
|
+
version = "1.11.1"
|
|
90
90
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
91
|
-
checksum = "
|
|
91
|
+
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
|
|
92
92
|
|
|
93
93
|
[[package]]
|
|
94
94
|
name = "cc"
|
|
95
|
-
version = "1.2.
|
|
95
|
+
version = "1.2.55"
|
|
96
96
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
97
|
-
checksum = "
|
|
97
|
+
checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
|
|
98
98
|
dependencies = [
|
|
99
99
|
"find-msvc-tools",
|
|
100
100
|
"shlex",
|
|
@@ -143,9 +143,9 @@ dependencies = [
|
|
|
143
143
|
|
|
144
144
|
[[package]]
|
|
145
145
|
name = "find-msvc-tools"
|
|
146
|
-
version = "0.1.
|
|
146
|
+
version = "0.1.9"
|
|
147
147
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
148
|
-
checksum = "
|
|
148
|
+
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
|
149
149
|
|
|
150
150
|
[[package]]
|
|
151
151
|
name = "form_urlencoded"
|
|
@@ -304,12 +304,11 @@ dependencies = [
|
|
|
304
304
|
|
|
305
305
|
[[package]]
|
|
306
306
|
name = "hyper-util"
|
|
307
|
-
version = "0.1.
|
|
307
|
+
version = "0.1.20"
|
|
308
308
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
309
|
-
checksum = "
|
|
309
|
+
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
|
|
310
310
|
dependencies = [
|
|
311
311
|
"bytes",
|
|
312
|
-
"futures-core",
|
|
313
312
|
"http",
|
|
314
313
|
"http-body",
|
|
315
314
|
"hyper",
|
|
@@ -428,9 +427,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|
|
428
427
|
|
|
429
428
|
[[package]]
|
|
430
429
|
name = "portable-atomic"
|
|
431
|
-
version = "1.13.
|
|
430
|
+
version = "1.13.1"
|
|
432
431
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
433
|
-
checksum = "
|
|
432
|
+
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|
434
433
|
|
|
435
434
|
[[package]]
|
|
436
435
|
name = "ppv-lite86"
|
|
@@ -570,6 +569,25 @@ dependencies = [
|
|
|
570
569
|
"windows-sys 0.52.0",
|
|
571
570
|
]
|
|
572
571
|
|
|
572
|
+
[[package]]
|
|
573
|
+
name = "rmp"
|
|
574
|
+
version = "0.8.15"
|
|
575
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
576
|
+
checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c"
|
|
577
|
+
dependencies = [
|
|
578
|
+
"num-traits",
|
|
579
|
+
]
|
|
580
|
+
|
|
581
|
+
[[package]]
|
|
582
|
+
name = "rmp-serde"
|
|
583
|
+
version = "1.3.1"
|
|
584
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
585
|
+
checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
|
|
586
|
+
dependencies = [
|
|
587
|
+
"rmp",
|
|
588
|
+
"serde",
|
|
589
|
+
]
|
|
590
|
+
|
|
573
591
|
[[package]]
|
|
574
592
|
name = "rustls"
|
|
575
593
|
version = "0.23.36"
|
|
@@ -701,9 +719,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
|
701
719
|
|
|
702
720
|
[[package]]
|
|
703
721
|
name = "slab"
|
|
704
|
-
version = "0.4.
|
|
722
|
+
version = "0.4.12"
|
|
705
723
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
706
|
-
checksum = "
|
|
724
|
+
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
|
|
707
725
|
|
|
708
726
|
[[package]]
|
|
709
727
|
name = "smallvec"
|
|
@@ -824,14 +842,14 @@ dependencies = [
|
|
|
824
842
|
|
|
825
843
|
[[package]]
|
|
826
844
|
name = "toolapi"
|
|
827
|
-
version = "0.1.
|
|
828
|
-
source = "git+https://github.com/mrx-org/toolapi.git#
|
|
845
|
+
version = "0.1.1"
|
|
846
|
+
source = "git+https://github.com/mrx-org/toolapi.git#0bf4075575b48abb8d0844433d5581aa2d81b72d"
|
|
829
847
|
dependencies = [
|
|
830
848
|
"axum",
|
|
831
849
|
"num-complex",
|
|
850
|
+
"rmp-serde",
|
|
832
851
|
"rustls",
|
|
833
852
|
"serde",
|
|
834
|
-
"serde_json",
|
|
835
853
|
"thiserror",
|
|
836
854
|
"tokio",
|
|
837
855
|
"tokio-tungstenite",
|
|
@@ -840,7 +858,7 @@ dependencies = [
|
|
|
840
858
|
|
|
841
859
|
[[package]]
|
|
842
860
|
name = "toolapi-py"
|
|
843
|
-
version = "0.1.
|
|
861
|
+
version = "0.1.1"
|
|
844
862
|
dependencies = [
|
|
845
863
|
"num-complex",
|
|
846
864
|
"pyo3",
|
|
@@ -1154,18 +1172,18 @@ checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
|
|
|
1154
1172
|
|
|
1155
1173
|
[[package]]
|
|
1156
1174
|
name = "zerocopy"
|
|
1157
|
-
version = "0.8.
|
|
1175
|
+
version = "0.8.37"
|
|
1158
1176
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1159
|
-
checksum = "
|
|
1177
|
+
checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac"
|
|
1160
1178
|
dependencies = [
|
|
1161
1179
|
"zerocopy-derive",
|
|
1162
1180
|
]
|
|
1163
1181
|
|
|
1164
1182
|
[[package]]
|
|
1165
1183
|
name = "zerocopy-derive"
|
|
1166
|
-
version = "0.8.
|
|
1184
|
+
version = "0.8.37"
|
|
1167
1185
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1168
|
-
checksum = "
|
|
1186
|
+
checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0"
|
|
1169
1187
|
dependencies = [
|
|
1170
1188
|
"proc-macro2",
|
|
1171
1189
|
"quote",
|
|
@@ -1180,6 +1198,6 @@ checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
|
|
1180
1198
|
|
|
1181
1199
|
[[package]]
|
|
1182
1200
|
name = "zmij"
|
|
1183
|
-
version = "1.0.
|
|
1201
|
+
version = "1.0.19"
|
|
1184
1202
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1185
|
-
checksum = "
|
|
1203
|
+
checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445"
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "code",
|
|
5
|
+
"execution_count": null,
|
|
6
|
+
"metadata": {
|
|
7
|
+
"colab": {
|
|
8
|
+
"base_uri": "https://localhost:8080/"
|
|
9
|
+
},
|
|
10
|
+
"collapsed": true,
|
|
11
|
+
"id": "GiA85Mp8NnVR",
|
|
12
|
+
"outputId": "6480281e-518e-4d94-9632-9ce6159eb9a6"
|
|
13
|
+
},
|
|
14
|
+
"outputs": [],
|
|
15
|
+
"source": [
|
|
16
|
+
"!pip install MRzeroCore\n",
|
|
17
|
+
"!pip install toolapi"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"cell_type": "code",
|
|
22
|
+
"execution_count": null,
|
|
23
|
+
"metadata": {
|
|
24
|
+
"colab": {
|
|
25
|
+
"base_uri": "https://localhost:8080/"
|
|
26
|
+
},
|
|
27
|
+
"collapsed": true,
|
|
28
|
+
"id": "G8exhuriPqYH",
|
|
29
|
+
"outputId": "987874de-1ab3-4021-bc42-ed35f27aaab2"
|
|
30
|
+
},
|
|
31
|
+
"outputs": [],
|
|
32
|
+
"source": [
|
|
33
|
+
"# @title Download sequence and phantom data\n",
|
|
34
|
+
"\n",
|
|
35
|
+
"!wget -q --show-progress https://github.com/mrx-org/toolapi-py/releases/download/v0.1.0/gre.seq\n",
|
|
36
|
+
"!wget -q --show-progress https://github.com/mrx-org/toolapi-py/releases/download/v0.1.0/brainweb-subj05-3T.json\n",
|
|
37
|
+
"!wget -q --show-progress https://github.com/mrx-org/toolapi-py/releases/download/v0.1.0/brainweb-subj05.nii.gz\n",
|
|
38
|
+
"!wget -q --show-progress https://github.com/mrx-org/toolapi-py/releases/download/v0.1.0/brainweb-subj05_dB0.nii.gz\n",
|
|
39
|
+
"!wget -q --show-progress https://github.com/mrx-org/toolapi-py/releases/download/v0.1.0/brainweb-subj05_B1+.nii.gz"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"cell_type": "code",
|
|
44
|
+
"execution_count": null,
|
|
45
|
+
"metadata": {
|
|
46
|
+
"id": "opV_JcaANzPs"
|
|
47
|
+
},
|
|
48
|
+
"outputs": [],
|
|
49
|
+
"source": [
|
|
50
|
+
"import MRzeroCore as mr0\n",
|
|
51
|
+
"import torch\n",
|
|
52
|
+
"import matplotlib.pyplot as plt\n",
|
|
53
|
+
"from time import time\n",
|
|
54
|
+
"\n",
|
|
55
|
+
"import toolapi"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"cell_type": "code",
|
|
60
|
+
"execution_count": null,
|
|
61
|
+
"metadata": {
|
|
62
|
+
"id": "ifDoRtEHWoQz"
|
|
63
|
+
},
|
|
64
|
+
"outputs": [],
|
|
65
|
+
"source": [
|
|
66
|
+
"# @title Helpers to convert between `toolapi` and `MRzeroCore`\n",
|
|
67
|
+
"def phantom_dict_to_toolapi(phantom: mr0.TissueDict) -> toolapi.value.MultiTissuePhantom:\n",
|
|
68
|
+
" tissues = list(phantom.values())\n",
|
|
69
|
+
" voxel_size = (tissues[0].size / torch.as_tensor(tissues[0].PD.shape)).tolist()\n",
|
|
70
|
+
"\n",
|
|
71
|
+
" return toolapi.value.MultiTissuePhantom(\n",
|
|
72
|
+
" \"AASinc\", # voxel shape type\n",
|
|
73
|
+
" voxel_size, # voxel shape data\n",
|
|
74
|
+
" voxel_size, # grid spacing\n",
|
|
75
|
+
" list(tissues[0].PD.shape), # grid size\n",
|
|
76
|
+
" # We assume that all tissues have the same B1 and coil_sens\n",
|
|
77
|
+
" tissues[0].B1.reshape(tissues[0].B1.shape[0], -1).tolist(),\n",
|
|
78
|
+
" tissues[0].coil_sens.reshape(tissues[0].coil_sens.shape[0], -1).tolist(),\n",
|
|
79
|
+
" [\n",
|
|
80
|
+
" (\n",
|
|
81
|
+
" tissue.PD.flatten().tolist(),\n",
|
|
82
|
+
" tissue.B0.flatten().tolist(),\n",
|
|
83
|
+
" toolapi.value.TissueProperties(\n",
|
|
84
|
+
" float(tissue.T1[tissue.PD > 0].mean()),\n",
|
|
85
|
+
" float(tissue.T2[tissue.PD > 0].mean()),\n",
|
|
86
|
+
" float(tissue.T2dash[tissue.PD > 0].mean()),\n",
|
|
87
|
+
" float(tissue.D[tissue.PD > 0].mean()),\n",
|
|
88
|
+
" )\n",
|
|
89
|
+
" )\n",
|
|
90
|
+
" for tissue in tissues\n",
|
|
91
|
+
" ]\n",
|
|
92
|
+
" )\n",
|
|
93
|
+
"\n",
|
|
94
|
+
"\n",
|
|
95
|
+
"def to_instant_events(seq: mr0.Sequence) -> toolapi.value.EventSeq:\n",
|
|
96
|
+
" ie_seq = []\n",
|
|
97
|
+
"\n",
|
|
98
|
+
" Event = toolapi.value.Event\n",
|
|
99
|
+
" for rep in seq:\n",
|
|
100
|
+
" ie_seq.append(Event.Pulse(rep.pulse.angle, rep.pulse.phase))\n",
|
|
101
|
+
" for ev in range(rep.event_count):\n",
|
|
102
|
+
" ie_seq.append(Event.Fid([\n",
|
|
103
|
+
" rep.gradm[ev, 0],\n",
|
|
104
|
+
" rep.gradm[ev, 1],\n",
|
|
105
|
+
" rep.gradm[ev, 2],\n",
|
|
106
|
+
" rep.event_time[ev]\n",
|
|
107
|
+
" ]))\n",
|
|
108
|
+
" if rep.adc_usage[ev] != 0:\n",
|
|
109
|
+
" ie_seq.append(Event.Adc(torch.pi / 2 - rep.adc_phase[ev]))\n",
|
|
110
|
+
"\n",
|
|
111
|
+
" ie_seq = toolapi.value.EventSeq(ie_seq)\n",
|
|
112
|
+
" return ie_seq"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"cell_type": "code",
|
|
117
|
+
"execution_count": null,
|
|
118
|
+
"metadata": {
|
|
119
|
+
"id": "gXB-6EyNuDOO"
|
|
120
|
+
},
|
|
121
|
+
"outputs": [],
|
|
122
|
+
"source": [
|
|
123
|
+
"# @title Define tools\n",
|
|
124
|
+
"def on_message(msg):\n",
|
|
125
|
+
" print(f\"\\r > {msg}\", end=\"\")\n",
|
|
126
|
+
" return True\n",
|
|
127
|
+
"\n",
|
|
128
|
+
"def load_seq(path, exact_trajectories=True):\n",
|
|
129
|
+
" with open(path) as f:\n",
|
|
130
|
+
" file_content = f.read()\n",
|
|
131
|
+
" result = toolapi.call(\n",
|
|
132
|
+
" \"wss://tool-seqloader-flyio.fly.dev/tool\",\n",
|
|
133
|
+
" on_message,\n",
|
|
134
|
+
" seq_file=file_content,\n",
|
|
135
|
+
" exact_trajectory=exact_trajectories\n",
|
|
136
|
+
" )\n",
|
|
137
|
+
" print(\"\\n --- done ---\")\n",
|
|
138
|
+
" return result[\"seq\"]\n",
|
|
139
|
+
"\n",
|
|
140
|
+
"# Define the simulation tool\n",
|
|
141
|
+
"def sim_spdg(sequence, phantom):\n",
|
|
142
|
+
" result = toolapi.call(\n",
|
|
143
|
+
" \"wss://tool-spdg-flyio.fly.dev/tool\",\n",
|
|
144
|
+
" on_message,\n",
|
|
145
|
+
" sequence=sequence,\n",
|
|
146
|
+
" phantom=phantom,\n",
|
|
147
|
+
" )\n",
|
|
148
|
+
" print(\"\\n --- done ---\")\n",
|
|
149
|
+
" return result[\"signal\"]"
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"cell_type": "code",
|
|
154
|
+
"execution_count": null,
|
|
155
|
+
"metadata": {
|
|
156
|
+
"colab": {
|
|
157
|
+
"base_uri": "https://localhost:8080/"
|
|
158
|
+
},
|
|
159
|
+
"collapsed": true,
|
|
160
|
+
"id": "h1cWrGG5XXm8",
|
|
161
|
+
"outputId": "36890490-d999-4aac-d105-a45ba237f070"
|
|
162
|
+
},
|
|
163
|
+
"outputs": [],
|
|
164
|
+
"source": [
|
|
165
|
+
"# @title Load phantom\n",
|
|
166
|
+
"seq_tool = load_seq(\"gre.seq\")\n",
|
|
167
|
+
"seq_mr0 = to_instant_events(mr0.Sequence.import_file(\"gre.seq\", exact_trajectories=False))\n",
|
|
168
|
+
"\n",
|
|
169
|
+
"# Colab can't handle the phantom at full resolution; reduce data a bit\n",
|
|
170
|
+
"config = mr0.NiftiPhantom.load(\"brainweb-subj05-3T.json\")\n",
|
|
171
|
+
"config.tissues.pop(\"fat\")\n",
|
|
172
|
+
"for tissue in config.tissues.values():\n",
|
|
173
|
+
" tissue.B1_tx = [1.0]\n",
|
|
174
|
+
" tissue.B1_rx = [1.0]\n",
|
|
175
|
+
"\n",
|
|
176
|
+
"phantom = mr0.TissueDict.load(\".\", config)\n",
|
|
177
|
+
"phantom = phantom.interpolate(64, 64, 64).slices([30])\n",
|
|
178
|
+
"phantom = phantom_dict_to_toolapi(phantom)"
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"cell_type": "code",
|
|
183
|
+
"execution_count": null,
|
|
184
|
+
"metadata": {
|
|
185
|
+
"colab": {
|
|
186
|
+
"base_uri": "https://localhost:8080/"
|
|
187
|
+
},
|
|
188
|
+
"id": "UD-euke_qLoN",
|
|
189
|
+
"outputId": "1dbea27d-b919-4754-d3d9-a7bc442759fc"
|
|
190
|
+
},
|
|
191
|
+
"outputs": [],
|
|
192
|
+
"source": [
|
|
193
|
+
"# @title Load sequence\n",
|
|
194
|
+
"seq_tool = load_seq(\"gre.seq\", exact_trajectories=True)\n",
|
|
195
|
+
"seq_mr0 = to_instant_events(mr0.Sequence.import_file(\"gre.seq\", exact_trajectories=True))"
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"cell_type": "code",
|
|
200
|
+
"execution_count": null,
|
|
201
|
+
"metadata": {
|
|
202
|
+
"colab": {
|
|
203
|
+
"base_uri": "https://localhost:8080/"
|
|
204
|
+
},
|
|
205
|
+
"id": "IUm9Zj6ijq00",
|
|
206
|
+
"outputId": "2973c887-b998-4726-f422-051d8e80b115"
|
|
207
|
+
},
|
|
208
|
+
"outputs": [],
|
|
209
|
+
"source": [
|
|
210
|
+
"# @title compare parsed sequences for differences\n",
|
|
211
|
+
"print(f\"event count: tool={len(seq_tool.events)}, mr0={len(seq_tool.events)}\")\n",
|
|
212
|
+
"\n",
|
|
213
|
+
"rf_angles = []\n",
|
|
214
|
+
"rf_phases = []\n",
|
|
215
|
+
"kt_x = []\n",
|
|
216
|
+
"kt_y = []\n",
|
|
217
|
+
"kt_z = []\n",
|
|
218
|
+
"kt_t = []\n",
|
|
219
|
+
"adc_phases = []\n",
|
|
220
|
+
"\n",
|
|
221
|
+
"for ev_tool, ev_mr0 in zip(seq_tool.events, seq_mr0.events):\n",
|
|
222
|
+
" if ev_tool.variant == 'Pulse':\n",
|
|
223
|
+
" rf_angles.append((ev_tool.fields['angle'], ev_mr0.fields['angle']))\n",
|
|
224
|
+
" rf_phases.append((ev_tool.fields['phase'], ev_mr0.fields['phase']))\n",
|
|
225
|
+
" elif ev_tool.variant == 'Fid':\n",
|
|
226
|
+
" kt_x.append((ev_tool.fields['kt'][0], ev_mr0.fields['kt'][0]))\n",
|
|
227
|
+
" kt_y.append((ev_tool.fields['kt'][1], ev_mr0.fields['kt'][1]))\n",
|
|
228
|
+
" kt_z.append((ev_tool.fields['kt'][2], ev_mr0.fields['kt'][2]))\n",
|
|
229
|
+
" kt_t.append((ev_tool.fields['kt'][3], ev_mr0.fields['kt'][3]))\n",
|
|
230
|
+
" elif ev_tool.variant == 'Adc':\n",
|
|
231
|
+
" adc_phases.append((ev_tool.fields['phase'], ev_mr0.fields['phase']))\n",
|
|
232
|
+
"\n",
|
|
233
|
+
"\n",
|
|
234
|
+
"print(f\"max diff in angle: {max(abs(x[0] - x[1]) for x in rf_angles)}\")\n",
|
|
235
|
+
"print(f\"max diff in phase: {max(abs(x[0] - x[1]) for x in rf_phases)}\")\n",
|
|
236
|
+
"print(f\"max diff in kt_x: {max(abs(x[0] - x[1]) for x in kt_x)}\")\n",
|
|
237
|
+
"print(f\"max diff in kt_y: {max(abs(x[0] - x[1]) for x in kt_y)}\")\n",
|
|
238
|
+
"print(f\"max diff in kt_z: {max(abs(x[0] - x[1]) for x in kt_z)}\")\n",
|
|
239
|
+
"print(f\"max diff in kt_t: {max(abs(x[0] - x[1]) for x in kt_t)}\")\n",
|
|
240
|
+
"print(f\"max diff in adc phase: {max(abs(x[0] - x[1]) for x in adc_phases)}\")\n",
|
|
241
|
+
"\n",
|
|
242
|
+
"# plt.figure()\n",
|
|
243
|
+
"# plt.plot([x[0] - x[1] for x in rf_angles], label=\"angle\")\n",
|
|
244
|
+
"# plt.plot([x[0] - x[1] for x in rf_phases], label=\"phase\")\n",
|
|
245
|
+
"# plt.plot([x[0] - x[1] for x in kt_x], label=\"kt_x\")\n",
|
|
246
|
+
"# plt.plot([x[0] - x[1] for x in kt_y], label=\"kt_y\")\n",
|
|
247
|
+
"# plt.plot([x[0] - x[1] for x in kt_z], label=\"kt_z\")\n",
|
|
248
|
+
"# plt.plot([x[0] - x[1] for x in kt_t], label=\"kt_t\")\n",
|
|
249
|
+
"# plt.legend()\n",
|
|
250
|
+
"# plt.grid()\n",
|
|
251
|
+
"# plt.show()"
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"cell_type": "code",
|
|
256
|
+
"execution_count": null,
|
|
257
|
+
"metadata": {
|
|
258
|
+
"colab": {
|
|
259
|
+
"base_uri": "https://localhost:8080/",
|
|
260
|
+
"height": 1000
|
|
261
|
+
},
|
|
262
|
+
"id": "G-39fS3ygxen",
|
|
263
|
+
"outputId": "f9e1d12b-2460-47e5-93d1-f8e58ad172ad"
|
|
264
|
+
},
|
|
265
|
+
"outputs": [],
|
|
266
|
+
"source": [
|
|
267
|
+
"# @title Run simulation on fly.io\n",
|
|
268
|
+
"start = time()\n",
|
|
269
|
+
"signal_tool = torch.tensor(sim_spdg(seq_tool, phantom))[0, :]\n",
|
|
270
|
+
"print(f\"took {time() - start:.3} s\")\n",
|
|
271
|
+
"start = time()\n",
|
|
272
|
+
"signal_mr0 = torch.tensor(sim_spdg(seq_mr0, phantom))[0, :]\n",
|
|
273
|
+
"print(f\"took {time() - start:.3} s\")\n",
|
|
274
|
+
"\n",
|
|
275
|
+
"reco_tool = torch.fft.fftshift(torch.fft.fft2(torch.fft.fftshift(signal_tool.reshape(256, 256))))\n",
|
|
276
|
+
"reco_mr0 = torch.fft.fftshift(torch.fft.fft2(torch.fft.fftshift(signal_mr0.reshape(256, 256))))\n",
|
|
277
|
+
"\n",
|
|
278
|
+
"# Small difference due to small deviations (order of 1e-7) between adc phases\n",
|
|
279
|
+
"plt.figure()\n",
|
|
280
|
+
"plt.suptitle(\"Difference\")\n",
|
|
281
|
+
"plt.subplot(121)\n",
|
|
282
|
+
"plt.imshow((reco_tool - reco_mr0).abs(), origin=\"lower\", vmin=0)\n",
|
|
283
|
+
"plt.axis(\"off\")\n",
|
|
284
|
+
"plt.colorbar()\n",
|
|
285
|
+
"plt.subplot(122)\n",
|
|
286
|
+
"plt.imshow((reco_tool - reco_mr0).angle(), origin=\"lower\", vmin=-torch.pi, vmax=torch.pi, cmap=\"twilight\")\n",
|
|
287
|
+
"plt.axis(\"off\")\n",
|
|
288
|
+
"plt.colorbar()\n",
|
|
289
|
+
"plt.show()\n",
|
|
290
|
+
"\n",
|
|
291
|
+
"for signal, title in [(signal_tool, \"Tool\"), (signal_mr0, \"MR0\")]:\n",
|
|
292
|
+
" kspace = signal.reshape(256, 256)\n",
|
|
293
|
+
" reco = torch.fft.fftshift(torch.fft.fft2(torch.fft.fftshift(kspace)))\n",
|
|
294
|
+
"\n",
|
|
295
|
+
" plt.figure()\n",
|
|
296
|
+
" plt.suptitle(title)\n",
|
|
297
|
+
" plt.subplot(211)\n",
|
|
298
|
+
" plt.plot(signal.abs())\n",
|
|
299
|
+
" plt.grid()\n",
|
|
300
|
+
" plt.subplot(223)\n",
|
|
301
|
+
" plt.imshow(reco.abs(), origin=\"lower\", vmin=0)\n",
|
|
302
|
+
" plt.axis(\"off\")\n",
|
|
303
|
+
" plt.subplot(224)\n",
|
|
304
|
+
" plt.imshow(reco.angle(), origin=\"lower\", vmin=-torch.pi, vmax=torch.pi, cmap=\"twilight\")\n",
|
|
305
|
+
" plt.axis(\"off\")\n",
|
|
306
|
+
" plt.show()\n"
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
],
|
|
310
|
+
"metadata": {
|
|
311
|
+
"colab": {
|
|
312
|
+
"provenance": []
|
|
313
|
+
},
|
|
314
|
+
"kernelspec": {
|
|
315
|
+
"display_name": "Python 3",
|
|
316
|
+
"name": "python3"
|
|
317
|
+
},
|
|
318
|
+
"language_info": {
|
|
319
|
+
"name": "python"
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
"nbformat": 4,
|
|
323
|
+
"nbformat_minor": 0
|
|
324
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "code",
|
|
5
|
+
"execution_count": null,
|
|
6
|
+
"metadata": {
|
|
7
|
+
"colab": {
|
|
8
|
+
"base_uri": "https://localhost:8080/"
|
|
9
|
+
},
|
|
10
|
+
"collapsed": true,
|
|
11
|
+
"id": "GiA85Mp8NnVR",
|
|
12
|
+
"outputId": "18f17ceb-69a3-4c39-a146-0c900d11441d"
|
|
13
|
+
},
|
|
14
|
+
"outputs": [],
|
|
15
|
+
"source": [
|
|
16
|
+
"!pip install toolapi\n",
|
|
17
|
+
"!wget -q --show-progress https://github.com/mrx-org/toolapi-py/releases/download/v0.1.0/gre.seq"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"cell_type": "code",
|
|
22
|
+
"execution_count": null,
|
|
23
|
+
"metadata": {
|
|
24
|
+
"id": "gXB-6EyNuDOO"
|
|
25
|
+
},
|
|
26
|
+
"outputs": [],
|
|
27
|
+
"source": [
|
|
28
|
+
"# @title Define tools\n",
|
|
29
|
+
"import toolapi\n",
|
|
30
|
+
"from functools import cache\n",
|
|
31
|
+
"\n",
|
|
32
|
+
"def on_message(msg):\n",
|
|
33
|
+
" print(f\"\\r > {msg}\", end=\"\")\n",
|
|
34
|
+
" return True\n",
|
|
35
|
+
"\n",
|
|
36
|
+
"def call(url, **kwargs):\n",
|
|
37
|
+
" from time import time\n",
|
|
38
|
+
" start = time()\n",
|
|
39
|
+
" result = toolapi.call(url, on_message, **kwargs)\n",
|
|
40
|
+
" print(f\"\\n --- done ({time() - start:.2f} s) ---\")\n",
|
|
41
|
+
" return result\n",
|
|
42
|
+
"\n",
|
|
43
|
+
"# .seq loader: uses disseqt to convert sequence to instant events\n",
|
|
44
|
+
"def load_seq(path, exact_trajectories=True):\n",
|
|
45
|
+
" with open(path) as f:\n",
|
|
46
|
+
" file_content = f.read()\n",
|
|
47
|
+
" return call(\n",
|
|
48
|
+
" \"wss://tool-seqloader-flyio.fly.dev/tool\",\n",
|
|
49
|
+
" seq_file=file_content,\n",
|
|
50
|
+
" exact_trajectory=exact_trajectories\n",
|
|
51
|
+
" )[\"seq\"]\n",
|
|
52
|
+
"\n",
|
|
53
|
+
"# phantom library: returns rescaled brainweb multi-tissue phantoms (slow)\n",
|
|
54
|
+
"@cache\n",
|
|
55
|
+
"def load_phantom(subject, res, slice):\n",
|
|
56
|
+
" return call(\n",
|
|
57
|
+
" \"wss://tool-phantomlib-flyio.fly.dev/tool\",\n",
|
|
58
|
+
" subject=subject, # BrainWeb subject 1-20\n",
|
|
59
|
+
" res_x=res[0], # X resolution (1-434)\n",
|
|
60
|
+
" res_y=res[1], # Y resolution (1-362)\n",
|
|
61
|
+
" res_z=res[2], # Z resolution (1-434)\n",
|
|
62
|
+
" slice=slice, # Axial slice index\n",
|
|
63
|
+
" )[\"phantom\"]\n",
|
|
64
|
+
"\n",
|
|
65
|
+
"# not-yet-quite segmented PDG\n",
|
|
66
|
+
"def sim_spdg(sequence, phantom):\n",
|
|
67
|
+
" return call(\n",
|
|
68
|
+
" \"wss://tool-spdg-flyio.fly.dev/tool\",\n",
|
|
69
|
+
" sequence=sequence,\n",
|
|
70
|
+
" phantom=phantom,\n",
|
|
71
|
+
" )[\"signal\"]"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"cell_type": "code",
|
|
76
|
+
"execution_count": null,
|
|
77
|
+
"metadata": {
|
|
78
|
+
"colab": {
|
|
79
|
+
"base_uri": "https://localhost:8080/",
|
|
80
|
+
"height": 475
|
|
81
|
+
},
|
|
82
|
+
"id": "G-39fS3ygxen",
|
|
83
|
+
"outputId": "e26eef10-da33-45a8-b8c1-00ec23cef04e"
|
|
84
|
+
},
|
|
85
|
+
"outputs": [],
|
|
86
|
+
"source": [
|
|
87
|
+
"# @title **load .seq + load phantom + run sim** | _with tools hosted on fly.io_\n",
|
|
88
|
+
"import numpy as np\n",
|
|
89
|
+
"import matplotlib.pyplot as plt\n",
|
|
90
|
+
"\n",
|
|
91
|
+
"seq = load_seq(\"gre.seq\", exact_trajectories=False)\n",
|
|
92
|
+
"phantom = load_phantom(4, (64, 64, 64), 30)\n",
|
|
93
|
+
"signal = np.array(sim_spdg(seq, phantom))[0, :]\n",
|
|
94
|
+
"\n",
|
|
95
|
+
"# Reconstruction is done here (not via some tool)\n",
|
|
96
|
+
"kspace = signal.reshape(256, 256)\n",
|
|
97
|
+
"reco = np.fft.fftshift(np.fft.fft2(np.fft.fftshift(kspace)))\n",
|
|
98
|
+
"\n",
|
|
99
|
+
"plt.figure()\n",
|
|
100
|
+
"plt.subplot(211)\n",
|
|
101
|
+
"plt.plot(np.abs(signal))\n",
|
|
102
|
+
"plt.grid()\n",
|
|
103
|
+
"plt.subplot(223)\n",
|
|
104
|
+
"plt.imshow(np.abs(reco), origin=\"lower\", vmin=0)\n",
|
|
105
|
+
"plt.axis(\"off\")\n",
|
|
106
|
+
"plt.subplot(224)\n",
|
|
107
|
+
"plt.imshow(np.angle(reco), origin=\"lower\", vmin=-np.pi, vmax=np.pi, cmap=\"twilight\")\n",
|
|
108
|
+
"plt.axis(\"off\")\n",
|
|
109
|
+
"plt.show()\n"
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
"metadata": {
|
|
114
|
+
"colab": {
|
|
115
|
+
"provenance": []
|
|
116
|
+
},
|
|
117
|
+
"kernelspec": {
|
|
118
|
+
"display_name": "Python 3",
|
|
119
|
+
"name": "python3"
|
|
120
|
+
},
|
|
121
|
+
"language_info": {
|
|
122
|
+
"name": "python"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"nbformat": 4,
|
|
126
|
+
"nbformat_minor": 0
|
|
127
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|