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.

@@ -86,15 +86,15 @@ dependencies = [
86
86
 
87
87
  [[package]]
88
88
  name = "bytes"
89
- version = "1.11.0"
89
+ version = "1.11.1"
90
90
  source = "registry+https://github.com/rust-lang/crates.io-index"
91
- checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
91
+ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
92
92
 
93
93
  [[package]]
94
94
  name = "cc"
95
- version = "1.2.54"
95
+ version = "1.2.55"
96
96
  source = "registry+https://github.com/rust-lang/crates.io-index"
97
- checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583"
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.8"
146
+ version = "0.1.9"
147
147
  source = "registry+https://github.com/rust-lang/crates.io-index"
148
- checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
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.19"
307
+ version = "0.1.20"
308
308
  source = "registry+https://github.com/rust-lang/crates.io-index"
309
- checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
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.0"
430
+ version = "1.13.1"
432
431
  source = "registry+https://github.com/rust-lang/crates.io-index"
433
- checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
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.11"
722
+ version = "0.4.12"
705
723
  source = "registry+https://github.com/rust-lang/crates.io-index"
706
- checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
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.0"
828
- source = "git+https://github.com/mrx-org/toolapi.git#c4a30afcd3a64d1a752c12d1d8f0c20d3f5f9613"
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.0"
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.35"
1175
+ version = "0.8.37"
1158
1176
  source = "registry+https://github.com/rust-lang/crates.io-index"
1159
- checksum = "fdea86ddd5568519879b8187e1cf04e24fce28f7fe046ceecbce472ff19a2572"
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.35"
1184
+ version = "0.8.37"
1167
1185
  source = "registry+https://github.com/rust-lang/crates.io-index"
1168
- checksum = "0c15e1b46eff7c6c91195752e0eeed8ef040e391cdece7c25376957d5f15df22"
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.17"
1201
+ version = "1.0.19"
1184
1202
  source = "registry+https://github.com/rust-lang/crates.io-index"
1185
- checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439"
1203
+ checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "toolapi-py"
3
- version = "0.1.0"
3
+ version = "0.1.1"
4
4
  edition = "2024"
5
5
  readme = "README.md"
6
6
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: toolapi
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -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