MRArbGrad 4.2.0__tar.gz → 4.4.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.
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0/MRArbGrad.egg-info}/PKG-INFO +1 -1
- {mrarbgrad-4.2.0/MRArbGrad.egg-info → mrarbgrad-4.4.0}/PKG-INFO +1 -1
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/Function.py +184 -48
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/Utility.py +118 -29
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/__init__.py +1 -1
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/MrTraj.h +2 -2
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/VDSpiral.h +13 -9
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/pyproject.toml +1 -1
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/LICENSE +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/MANIFEST.in +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/MRArbGrad.egg-info/SOURCES.txt +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/MRArbGrad.egg-info/dependency_links.txt +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/MRArbGrad.egg-info/requires.txt +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/MRArbGrad.egg-info/top_level.txt +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/README.md +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/example/example_BuiltInTraj.py +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/example/example_ExternalFunction2D.py +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/example/example_ExternalSamples2D.py +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/example/example_ExternalSamples3D.py +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/mag/Mag.cpp +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/mag/Mag.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/main.cpp +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/Cones.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/MrTraj_2D.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/Rosette.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/Seiffert.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/Shell3d.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/Spiral.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/TrajFunc.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/traj/Yarnball.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/utility/Intp.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/utility/LinIntp.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/utility/SplineIntp.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/utility/global.cpp +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/utility/global.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/utility/v3.cpp +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/ext/utility/v3.h +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/trajfunc/__init__.py +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/mrarbgrad_src/trajfunc/main.py +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/setup.cfg +0 -0
- {mrarbgrad-4.2.0 → mrarbgrad-4.4.0}/setup.py +0 -0
|
@@ -23,10 +23,24 @@ def calGrad4ExFunc\
|
|
|
23
23
|
p0:float64 = 0e0,
|
|
24
24
|
p1:float64 = 1e0,
|
|
25
25
|
) -> tuple[NDArray, NDArray]:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
"""
|
|
27
|
+
Generate gradient waveforms for external functions.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
31
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
32
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
33
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
34
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
35
|
+
getK (Callable | None, optional): Trajectory function.
|
|
36
|
+
getDkDp (Callable | None, optional): 1st order derivative to trajectory function.
|
|
37
|
+
getD2kDp2 (Callable | None, optional): 2nd order derivative to trajectory function.
|
|
38
|
+
p0 (float64, optional): Lower bound of the trajectory parameter.
|
|
39
|
+
p1 (float64, optional): Upper bound of the trajectory parameter.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
tuple[NDArray, NDArray]: Gradient waveform (in `Hz/pix`); Corresponding parameter
|
|
43
|
+
"""
|
|
30
44
|
return ext.calGrad4ExFunc\
|
|
31
45
|
(
|
|
32
46
|
float64(fov),
|
|
@@ -55,10 +69,20 @@ def calGrad4ExSamp\
|
|
|
55
69
|
|
|
56
70
|
arrK: NDArray = np.empty((0,3)),
|
|
57
71
|
) -> tuple[NDArray, NDArray]:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
"""
|
|
73
|
+
Generate gradient waveforms for external trajectory samples.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
77
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
78
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
79
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
80
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
81
|
+
arrK (NDArray, optional): External trajectory samples, shape: `[nK,nAx]`
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
tuple[NDArray, NDArray]: Gradient waveform (in `Hz/pix`); Corresponding parameter
|
|
85
|
+
"""
|
|
62
86
|
return ext.calGrad4ExSamp\
|
|
63
87
|
(
|
|
64
88
|
float64(fov),
|
|
@@ -83,10 +107,21 @@ def getG_Spiral\
|
|
|
83
107
|
nSlice: int64 = 1,
|
|
84
108
|
kRhoPhi: float64 = 0.5 / (4 * pi)
|
|
85
109
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
110
|
+
"""
|
|
111
|
+
Generate gradient waveforms for a standard spiral trajectory.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
115
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
116
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
117
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
118
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
119
|
+
nSlice (int64, optional): Number of slices.
|
|
120
|
+
kRhoPhi (float64, optional): Shape parameter.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
124
|
+
"""
|
|
90
125
|
return ext.getG_Spiral\
|
|
91
126
|
(
|
|
92
127
|
float64(fov),
|
|
@@ -113,10 +148,22 @@ def getG_VDSpiral\
|
|
|
113
148
|
kRhoPhi0: float64 = 0.5 / (8 * pi),
|
|
114
149
|
kRhoPhi1: float64 = 0.5 / (2 * pi),
|
|
115
150
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
151
|
+
"""
|
|
152
|
+
Generate gradient waveforms for a variable density (VD) spiral trajectory.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
156
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
157
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
158
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
159
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
160
|
+
nSlice (int64, optional): Number of slices.
|
|
161
|
+
kRhoPhi0 (float64, optional): Inner shape parameter.
|
|
162
|
+
kRhoPhi1 (float64, optional): Outer shape parameter.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
166
|
+
"""
|
|
120
167
|
return ext.getG_VDSpiral\
|
|
121
168
|
(
|
|
122
169
|
float64(fov),
|
|
@@ -143,10 +190,21 @@ def getG_VDSpiral_RT\
|
|
|
143
190
|
kRhoPhi0: float64 = 0.5 / (8 * pi),
|
|
144
191
|
kRhoPhi1: float64 = 0.5 / (2 * pi),
|
|
145
192
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
193
|
+
"""
|
|
194
|
+
Generate gradient waveforms for a real-time variable density spiral trajectory.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
198
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
199
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
200
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
201
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
202
|
+
kRhoPhi0 (float64, optional): Inner shape parameter.
|
|
203
|
+
kRhoPhi1 (float64, optional): Outer shape parameter.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
207
|
+
"""
|
|
150
208
|
return ext.getG_VDSpiral_RT\
|
|
151
209
|
(
|
|
152
210
|
float64(fov),
|
|
@@ -174,10 +232,23 @@ def getG_Rosette\
|
|
|
174
232
|
om2: float64 = 3*pi,
|
|
175
233
|
tMax: float64 = 1e0,
|
|
176
234
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
235
|
+
"""
|
|
236
|
+
Generate gradient waveforms for a rosette trajectory.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
240
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
241
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
242
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
243
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
244
|
+
nSlice (int64, optional): Number of slices.
|
|
245
|
+
om1 (float64, optional): Shape parameter.
|
|
246
|
+
om2 (float64, optional): Shape parameter.
|
|
247
|
+
tMax (float64, optional): Shape parameter.
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
251
|
+
"""
|
|
181
252
|
return ext.getG_Rosette\
|
|
182
253
|
(
|
|
183
254
|
float64(fov),
|
|
@@ -208,10 +279,24 @@ def getG_Rosette_Trad\
|
|
|
208
279
|
tMax: float64 = 1e0,
|
|
209
280
|
tAcq: float64 = 2.523e-3,
|
|
210
281
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
282
|
+
"""
|
|
283
|
+
Generate gradient waveforms for a traditional rosette trajectory.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
287
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
288
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
289
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
290
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
291
|
+
nSlice (int64, optional): Number of slices.
|
|
292
|
+
om1 (float64, optional): Shape parameter.
|
|
293
|
+
om2 (float64, optional): Shape parameter.
|
|
294
|
+
tMax (float64, optional): Shape parameter.
|
|
295
|
+
tAcq (float64, optional): Acquisition duration.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
299
|
+
"""
|
|
215
300
|
return ext.getG_Rosette_Trad\
|
|
216
301
|
(
|
|
217
302
|
float64(fov),
|
|
@@ -239,10 +324,20 @@ def getG_Shell3d\
|
|
|
239
324
|
|
|
240
325
|
kRhoTht: float64 = 0.5 / (2 * pi),
|
|
241
326
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
327
|
+
"""
|
|
328
|
+
Generate gradient waveforms for a 3D shell trajectory.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
332
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
333
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
334
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
335
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
336
|
+
kRhoTht (float64, optional): Shape parameter.
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
340
|
+
"""
|
|
246
341
|
return ext.getG_Shell3d\
|
|
247
342
|
(
|
|
248
343
|
float64(fov),
|
|
@@ -266,10 +361,20 @@ def getG_Yarnball\
|
|
|
266
361
|
|
|
267
362
|
kRhoPhi: float64 = 0.5 / (2 * pi),
|
|
268
363
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
364
|
+
"""
|
|
365
|
+
Generate gradient waveforms for a yarnball trajectory.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
369
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
370
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
371
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
372
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
373
|
+
kRhoPhi (float64, optional): Shape parameter.
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
377
|
+
"""
|
|
273
378
|
return ext.getG_Yarnball\
|
|
274
379
|
(
|
|
275
380
|
float64(fov),
|
|
@@ -293,10 +398,20 @@ def getG_Yarnball_RT\
|
|
|
293
398
|
|
|
294
399
|
kRhoPhi: float64 = 0.5 / (2 * pi)
|
|
295
400
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
401
|
+
"""
|
|
402
|
+
Generate gradient waveforms for a real-time yarnball trajectory.
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
406
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
407
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
408
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
409
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
410
|
+
kRhoPhi (float64, optional): Shape parameter.
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
414
|
+
"""
|
|
300
415
|
return ext.getG_Yarnball_RT\
|
|
301
416
|
(
|
|
302
417
|
float64(fov),
|
|
@@ -321,10 +436,21 @@ def getG_Seiffert\
|
|
|
321
436
|
m: float64 = 0.07,
|
|
322
437
|
uMax: float64 = 20.0,
|
|
323
438
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
439
|
+
"""
|
|
440
|
+
Generate gradient waveforms for a Seiffert spiral trajectory.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
444
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
445
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
446
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
447
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
448
|
+
m (float64, optional): Shape parameter.
|
|
449
|
+
uMax (float64, optional): Shape parameter.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
453
|
+
"""
|
|
328
454
|
return ext.getG_Seiffert\
|
|
329
455
|
(
|
|
330
456
|
float64(fov),
|
|
@@ -349,10 +475,20 @@ def getG_Cones\
|
|
|
349
475
|
|
|
350
476
|
kRhoPhi: float64 = 0.5 / (4 * pi),
|
|
351
477
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
478
|
+
"""
|
|
479
|
+
Generate gradient waveforms for a 3D cones trajectory.
|
|
480
|
+
|
|
481
|
+
Args:
|
|
482
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
483
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
484
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
485
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
486
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
487
|
+
kRhoPhi (float64, optional): Shape parameter.
|
|
488
|
+
|
|
489
|
+
Returns:
|
|
490
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
491
|
+
"""
|
|
356
492
|
return ext.getG_Cones\
|
|
357
493
|
(
|
|
358
494
|
float64(fov),
|
|
@@ -1,12 +1,93 @@
|
|
|
1
1
|
from numpy import *
|
|
2
2
|
from numpy.linalg import norm
|
|
3
3
|
from numpy.typing import *
|
|
4
|
+
from itertools import product
|
|
4
5
|
|
|
5
6
|
goldrat = (1+sqrt(5))/2
|
|
6
7
|
goldang = (2*pi)/(1+goldrat)
|
|
7
8
|
|
|
8
|
-
getGoldrat
|
|
9
|
-
getGoldang
|
|
9
|
+
def getGoldrat()->float: return goldrat
|
|
10
|
+
def getGoldang()->float: return goldang
|
|
11
|
+
|
|
12
|
+
def unitcvt(x:float, fov:float, nPix:int, dir:int, gamma:float=42.5756e6) -> float:
|
|
13
|
+
"""
|
|
14
|
+
This package uses `Hz/pix` for gradient unit, and `Hz/pix/s` for slew unit, and `pix` for length unit. This unit system has several good properties for theory derivation. You may need this helper function for unit conversion in case you are not familiar with this unit system.
|
|
15
|
+
|
|
16
|
+
You may need `dir=1,2` to convert common units (like `mT/m` for gradient and `T/m/s` for slew) to units supported by this package (like `Hz/pix` for gradient and `Hz/pix/s` for slew), before you call any gradient generation functions, or `dir=-1` when converting gradients generated by this package in `Hz/pix` back to `mT/m`.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
x (float): Input value.
|
|
20
|
+
fov (float): Field of view.
|
|
21
|
+
nPix (int): Number of pixels.
|
|
22
|
+
dir (int):
|
|
23
|
+
`1`: from `mT/m` to `Hz/pix`.
|
|
24
|
+
`2`: from `T/m/s` to `Hz/pix/s`.
|
|
25
|
+
`-1`: from `Hz/pix` to `mT/m`.
|
|
26
|
+
`-2`: from `Hz/pix/s` to `T/m/s`.
|
|
27
|
+
gamma (float): Gyromagnetic ratio `Hz/T`.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
float: Converted value.
|
|
31
|
+
"""
|
|
32
|
+
if dir==1:
|
|
33
|
+
return x * (1e-3*gamma*fov/nPix)
|
|
34
|
+
if dir==2:
|
|
35
|
+
return x * (gamma*fov/nPix)
|
|
36
|
+
if dir==-1:
|
|
37
|
+
return x / (1e-3*gamma*fov/nPix)
|
|
38
|
+
if dir==-2:
|
|
39
|
+
return x / (gamma*fov/nPix)
|
|
40
|
+
raise RuntimeError("dir")
|
|
41
|
+
|
|
42
|
+
def getK_Cartesian(nPix:int, nAx:int) -> list[NDArray]:
|
|
43
|
+
"""
|
|
44
|
+
Generates a Cartesian sampling pattern.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
nPix (int): Number of pixels.
|
|
48
|
+
nAx (int): Number of dimensions.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
list[NDArray]: List of trajectories in `[nK,nAx]`.
|
|
52
|
+
"""
|
|
53
|
+
arrK1D = linspace(-0.5, 0.5, nPix, endpoint=0)
|
|
54
|
+
lstArrK:list[NDArray] = []
|
|
55
|
+
|
|
56
|
+
for arrKyKz in product(arrK1D, repeat=nAx-1):
|
|
57
|
+
arrK = empty((nPix,nAx), dtype=float32)
|
|
58
|
+
arrK[:,0] = arrK1D
|
|
59
|
+
arrK[:,1:] = arrKyKz
|
|
60
|
+
lstArrK.append(arrK)
|
|
61
|
+
|
|
62
|
+
return lstArrK
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def getK_Radial(nPix:int, nAx:int, nSpoke:int, enGoldAng:bool) -> list:
|
|
66
|
+
"""
|
|
67
|
+
Generates a Radial sampling pattern.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
nPix (int): Number of pixels.
|
|
71
|
+
nAx (int): Number of dimensions.
|
|
72
|
+
nSpoke (int): Number of radial spokes.
|
|
73
|
+
enGoldAng (bool): If True, uses the golden angle for spoke spacing.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
list: A list of numpy arrays, each of shape [nPix, nAx], representing radial spokes.
|
|
77
|
+
"""
|
|
78
|
+
if nAx!=2: raise NotImplementedError("nAx!=2")
|
|
79
|
+
lstArrK = []
|
|
80
|
+
arrK1D = linspace(-0.5, 0.5, nPix, endpoint=0)
|
|
81
|
+
|
|
82
|
+
for iSpoke in range(nSpoke):
|
|
83
|
+
if enGoldAng: tht = iSpoke * goldang
|
|
84
|
+
else: tht = iSpoke * (pi / nSpoke)
|
|
85
|
+
arrK = empty((nPix,nAx), dtype=float32)
|
|
86
|
+
arrK[:,0] = arrK1D * cos(tht)
|
|
87
|
+
arrK[:,1] = arrK1D * sin(tht)
|
|
88
|
+
lstArrK.append(arrK)
|
|
89
|
+
|
|
90
|
+
return lstArrK
|
|
10
91
|
|
|
11
92
|
def gradClip(lstArrGrad:list[NDArray]|NDArray, dt:float, sLim:float, gLim:float) -> list[NDArray]|NDArray:
|
|
12
93
|
"""
|
|
@@ -55,71 +136,79 @@ def rand3d(i:int|NDArray, nAx:int=3, kx=sqrt(2), ky=sqrt(3), kz=sqrt(7)) -> NDAr
|
|
|
55
136
|
(i**2 * 1/(1+ky))%1,
|
|
56
137
|
(i**3 * 1/(1+kz))%1
|
|
57
138
|
][:nAx]).T
|
|
139
|
+
|
|
140
|
+
def genPermTab(n:int) -> list[int]:
|
|
141
|
+
inc = around(n*(goldrat-1)).astype(int64)
|
|
142
|
+
while gcd(inc,n)!=1: inc-=1
|
|
143
|
+
lstIdx = []
|
|
144
|
+
for i in range(n):
|
|
145
|
+
lstIdx.append(i*inc%n)
|
|
146
|
+
return lstIdx
|
|
58
147
|
|
|
59
|
-
def cvtGrad2Traj(
|
|
148
|
+
def cvtGrad2Traj(arrGrad:NDArray, dtGrad:int|float, dtAdc:int|float, nShift:int|float=1.0) -> tuple[NDArray, NDArray]:
|
|
60
149
|
"""
|
|
61
150
|
# description:
|
|
62
151
|
interpolate gradient waveform and calculate trajectory
|
|
63
152
|
|
|
64
153
|
# parameter
|
|
65
|
-
`
|
|
66
|
-
`dtGrad`, `
|
|
154
|
+
`arrGrad`: array of gradient waveform
|
|
155
|
+
`dtGrad`, `dtAdc`: temporal resolution of gradient system and ADC
|
|
67
156
|
|
|
68
157
|
# return:
|
|
69
158
|
interpolated trajectory and gradient
|
|
70
159
|
"""
|
|
71
|
-
dtShift = nShift*
|
|
72
|
-
nGrad,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
for iDim in range(
|
|
76
|
-
|
|
77
|
-
arrDk = zeros_like(
|
|
78
|
-
arrDk[0,:] = (
|
|
79
|
-
arrDk[1:,:] = (
|
|
160
|
+
dtShift = nShift*dtAdc
|
|
161
|
+
nGrad, nAx = arrGrad.shape
|
|
162
|
+
nAdc = int(dtGrad/dtAdc)*(nGrad-1)
|
|
163
|
+
arrGrad_Resamp = zeros([nAdc,nAx], dtype=float64)
|
|
164
|
+
for iDim in range(nAx):
|
|
165
|
+
arrGrad_Resamp[:,iDim] = interp(dtAdc*arange(nAdc)+dtShift, dtGrad*arange(nGrad), arrGrad[:,iDim])
|
|
166
|
+
arrDk = zeros_like(arrGrad_Resamp)
|
|
167
|
+
arrDk[0,:] = (arrGrad[0,:] + arrGrad_Resamp[0,:])*dtShift/2
|
|
168
|
+
arrDk[1:,:] = (arrGrad_Resamp[:-1] + arrGrad_Resamp[1:])*dtAdc/2
|
|
80
169
|
arrK = cumsum(arrDk,axis=0)
|
|
81
|
-
return arrK,
|
|
170
|
+
return arrK, arrGrad_Resamp
|
|
82
171
|
|
|
83
|
-
def delGrad(
|
|
172
|
+
def delGrad(arrGrad:NDArray, tau:int|float) -> NDArray:
|
|
84
173
|
"""
|
|
85
174
|
# description:
|
|
86
175
|
delay the input gradient waveform by time constant tau
|
|
87
176
|
|
|
88
177
|
# parameter
|
|
89
|
-
`
|
|
178
|
+
`arrGrad`: array of single gradient waveform
|
|
90
179
|
`tau`: time constant in RL circuit transfer function
|
|
91
180
|
|
|
92
181
|
# return:
|
|
93
182
|
delayed gradient waveform
|
|
94
183
|
"""
|
|
95
|
-
assert
|
|
96
|
-
if tau == 0: return
|
|
97
|
-
nPt, nAx =
|
|
184
|
+
assert arrGrad.ndim == 2, "only single gradient waveform is supported."
|
|
185
|
+
if tau == 0: return arrGrad.copy() # avoid divided-by-0 later
|
|
186
|
+
nPt, nAx = arrGrad.shape
|
|
98
187
|
|
|
99
188
|
# perform oversample to get better impluse response profile
|
|
100
189
|
ov = clip(10/tau, 1, 1e3).astype(int64) # the smaller the ov, the bigger oversampling is needed
|
|
101
|
-
|
|
190
|
+
arrGrad_ov = zeros([nPt*ov,nAx], dtype=arrGrad.dtype)
|
|
102
191
|
for iAx in range(nAx):
|
|
103
|
-
|
|
192
|
+
arrGrad_ov[:,iAx] = interp(linspace(0,nPt,nPt*ov,0), linspace(0,nPt,nPt,0), arrGrad[:,iAx]) # oversample
|
|
104
193
|
nPt *= ov
|
|
105
194
|
tau *= ov
|
|
106
195
|
|
|
107
196
|
# derive impluse response of RL circuit
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
197
|
+
arrGrad_Pad = zeros_like(arrGrad_ov)
|
|
198
|
+
arrGrad_Pad[:nPt//2,:] = arrGrad_ov[-1:,:]
|
|
199
|
+
arrGrad_Pad[nPt//2:,:] = arrGrad_ov[:1,:]
|
|
200
|
+
arrGrad_ov = concatenate([arrGrad_ov, arrGrad_Pad], axis=0)
|
|
112
201
|
arrT = linspace(0,2*nPt,2*nPt,0) + 0.5
|
|
113
202
|
arrImpResRL = (1/tau)*exp(-arrT/tau)
|
|
114
203
|
if abs(arrImpResRL.sum() - 1) > 1e-2: raise ValueError(f"arrImpResRL.sum() = {arrImpResRL.sum():.2f} (supposed to be 1) (tau too small or too large)")
|
|
115
204
|
|
|
116
205
|
# perform convolution between input waveform and impulse response
|
|
117
|
-
|
|
206
|
+
arrGrad_ov = fft.ifft(fft.fft(arrGrad_ov,axis=0)*fft.fft(arrImpResRL)[:,newaxis], axis=0).real
|
|
118
207
|
|
|
119
208
|
# de-oversample
|
|
120
|
-
|
|
209
|
+
arrGrad = arrGrad_ov[:nPt:ov,:]
|
|
121
210
|
|
|
122
|
-
return
|
|
211
|
+
return arrGrad
|
|
123
212
|
|
|
124
213
|
def rotate(arr:NDArray, ang:float64, axis:int64) -> NDArray:
|
|
125
214
|
if axis==0: # x
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from .Function import calGrad4ExFunc, calGrad4ExSamp
|
|
2
2
|
from .Function import getG_Cones, getG_Rosette, getG_Rosette_Trad, getG_Seiffert, getG_Shell3d, getG_Spiral, getG_VDSpiral, getG_VDSpiral_RT, getG_Yarnball, getG_Yarnball_RT
|
|
3
3
|
from .Function import setSolverMtg, setTrajRev, setGoldAng, setShuf, setMaxG0, setMaxG1, setMagGradSamp, setMagTrajSamp, setMagOverSamp, setMagSFS, setMagGradRep, setMagTrajRep, setDbgPrint, saveF64, loadF64, saveF32, loadF32
|
|
4
|
-
from .Utility import _calDiaphony, rotate, _calJacElip, _calCompElipInt, _calSphFibPt, cvtGrad2Traj, getGoldang, getGoldrat, rand3d, gradClip
|
|
4
|
+
from .Utility import _calDiaphony, rotate, _calJacElip, _calCompElipInt, _calSphFibPt, cvtGrad2Traj, getGoldang, getGoldrat, rand3d, gradClip, genPermTab
|
|
5
5
|
|
|
6
6
|
from . import trajfunc
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
bool gMrTraj_enMtg = false; // whether to use Lustig's minTimeGrad solver
|
|
14
14
|
f64 gMrTraj_g0Norm = 0e0; // initial gradient amplitude
|
|
15
15
|
f64 gMrTraj_g1Norm = 0e0; // final gradient amplitude
|
|
16
|
-
i64 gMrTraj_nGradSampRsv = 10000; // buffer size of
|
|
16
|
+
i64 gMrTraj_nGradSampRsv = 10000; // buffer size of MAG solver
|
|
17
17
|
i64 gMrTraj_nTrajSampRsv = 10000; // num. of samp. when doing Traj. Rep.
|
|
18
18
|
|
|
19
19
|
/*
|
|
@@ -204,7 +204,7 @@ protected:
|
|
|
204
204
|
minRotang = std::min(minRotang, rotang);
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
// ensure the rot. Num. is
|
|
207
|
+
// ensure the rot. Num. is an integer
|
|
208
208
|
return (i64)std::ceil(2e0*M_PI/minRotang);
|
|
209
209
|
}
|
|
210
210
|
|
|
@@ -14,7 +14,10 @@ public:
|
|
|
14
14
|
m_phi0 = phi0;
|
|
15
15
|
|
|
16
16
|
m_p0 = 0e0;
|
|
17
|
-
|
|
17
|
+
if (m_kRhoPhi0!=m_kRhoPhi1)
|
|
18
|
+
{ m_p1 = (std::log(kRhoPhi1)-std::log(kRhoPhi0)) / (2e0*(kRhoPhi1-kRhoPhi0)); }
|
|
19
|
+
else
|
|
20
|
+
{ m_p1 = 0.5e0/kRhoPhi0; }
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
virtual bool getK(v3* k, f64 p)
|
|
@@ -22,7 +25,11 @@ public:
|
|
|
22
25
|
if (k==NULL) return false;
|
|
23
26
|
|
|
24
27
|
f64& phi = p;
|
|
25
|
-
f64 rho
|
|
28
|
+
f64 rho;
|
|
29
|
+
if (m_kRhoPhi0!=m_kRhoPhi1)
|
|
30
|
+
{ rho = m_kRhoPhi0*(std::exp(2e0*(m_kRhoPhi1 - m_kRhoPhi0)*phi) - 1e0) / (2e0*(m_kRhoPhi1 - m_kRhoPhi0)); }
|
|
31
|
+
else
|
|
32
|
+
{ rho = m_kRhoPhi0*phi; }
|
|
26
33
|
k->x = rho * std::cos(phi + m_phi0);
|
|
27
34
|
k->y = rho * std::sin(phi + m_phi0);
|
|
28
35
|
k->z = 0e0;
|
|
@@ -39,19 +46,16 @@ protected:
|
|
|
39
46
|
class VDSpiral: public MrTraj_2D
|
|
40
47
|
{
|
|
41
48
|
public:
|
|
42
|
-
VDSpiral(const GeoPara& objGeoPara, const GradPara& objGradPara, i64 nStack, f64 kRhoPhi0, f64
|
|
49
|
+
VDSpiral(const GeoPara& objGeoPara, const GradPara& objGradPara, i64 nStack, f64 kRhoPhi0, f64 kRhoPhi1):
|
|
43
50
|
MrTraj_2D(objGeoPara,objGradPara,0,0,0,0,v3(),vv3())
|
|
44
51
|
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
m_ptfBaseTraj = new VDSpiral_TrajFunc(kRhoPhi0, dRhoPhi1);
|
|
52
|
+
m_ptfBaseTraj = new VDSpiral_TrajFunc(kRhoPhi0, kRhoPhi1);
|
|
48
53
|
ASSERT(m_ptfBaseTraj!=NULL);
|
|
49
54
|
m_nStack = nStack;
|
|
50
55
|
|
|
51
|
-
i64 nRot = calNRot(std::max(kRhoPhi0,
|
|
56
|
+
i64 nRot = calNRot(std::max(kRhoPhi0, kRhoPhi1), m_objGeoPara.nPix);
|
|
52
57
|
m_rotang = calRotAng(nRot);
|
|
53
58
|
m_nAcq = nRot*m_nStack;
|
|
54
|
-
PRINT(m_nAcq) // TEST
|
|
55
59
|
|
|
56
60
|
calGrad(&m_v3BaseM0PE, &m_vv3BaseGRO, NULL, *m_ptfBaseTraj, m_objGradPara);
|
|
57
61
|
m_nSampMax = m_vv3BaseGRO.size();
|
|
@@ -78,7 +82,7 @@ public:
|
|
|
78
82
|
{
|
|
79
83
|
m_kRhoPhi0 = kRhoPhi0;
|
|
80
84
|
m_kRhoPhi1 = kRhoPhi1;
|
|
81
|
-
m_nAcq = calNRot(kRhoPhi1, objGeoPara.nPix);
|
|
85
|
+
m_nAcq = calNRot(std::max(kRhoPhi0, kRhoPhi1), objGeoPara.nPix);
|
|
82
86
|
m_dRotAng = 2e0*M_PI/m_nAcq;
|
|
83
87
|
genPermTab(&m_vi64PermTab, m_nAcq);
|
|
84
88
|
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|