MRArbGrad 2.0.1__tar.gz → 2.1.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.
Files changed (44) hide show
  1. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0/MRArbGrad.egg-info}/PKG-INFO +9 -6
  2. {mrarbgrad-2.0.1/MRArbGrad.egg-info → mrarbgrad-2.1.0}/PKG-INFO +9 -6
  3. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/README.md +8 -5
  4. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/example/example_BuiltInTraj.py +4 -2
  5. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/example/example_ExternalFunction2D.py +15 -14
  6. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/example/example_ExternalSamples2D.py +11 -10
  7. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/example/example_ExternalSamples3D.py +11 -10
  8. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/Utility.py +41 -1
  9. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/__init__.py +1 -1
  10. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/mag/Mag.cpp +16 -16
  11. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/mag/Mag.h +5 -5
  12. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/main.cpp +1 -1
  13. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/MrTraj.h +12 -12
  14. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/TrajFunc.h +1 -1
  15. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/pyproject.toml +2 -2
  16. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/LICENSE +0 -0
  17. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/MANIFEST.in +0 -0
  18. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/MRArbGrad.egg-info/SOURCES.txt +0 -0
  19. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/MRArbGrad.egg-info/dependency_links.txt +0 -0
  20. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/MRArbGrad.egg-info/requires.txt +0 -0
  21. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/MRArbGrad.egg-info/top_level.txt +0 -0
  22. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/Function.py +0 -0
  23. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/TrajFunc.py +0 -0
  24. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/mag/GradGen.cpp +0 -0
  25. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/mag/GradGen.h +0 -0
  26. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/Cones.h +0 -0
  27. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/MrTraj_2D.h +0 -0
  28. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/Rosette.h +0 -0
  29. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/Seiffert.h +0 -0
  30. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/Shell3d.h +0 -0
  31. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/Spiral.h +0 -0
  32. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/VarDenSpiral.h +0 -0
  33. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/traj/Yarnball.h +0 -0
  34. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/utility/Intp.h +0 -0
  35. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/utility/LinIntp.h +0 -0
  36. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/utility/SplineIntp.h +0 -0
  37. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/utility/global.cpp +0 -0
  38. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/utility/global.h +0 -0
  39. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/utility/v3.cpp +0 -0
  40. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/ext/utility/v3.h +0 -0
  41. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/trajfunc/__init__.py +0 -0
  42. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/mrarbgrad_src/trajfunc/main.py +0 -0
  43. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/setup.cfg +0 -0
  44. {mrarbgrad-2.0.1 → mrarbgrad-2.1.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MRArbGrad
3
- Version: 2.0.1
3
+ Version: 2.1.0
4
4
  Summary: Gradient waveform design tool for arbitrary k-space trajectories.
5
5
  Author-email: Ryan <ryan_shanghaitech@proton.me>
6
6
  License-Expression: MIT
@@ -22,18 +22,21 @@ This toolbox is a pip package with C++ backend. The pip package can be called vi
22
22
  ```bash
23
23
  $ conda create -n magtest -y
24
24
  $ conda activate magtest
25
- $ conda install python==3.10 -y
25
+ $ conda install python==3.12 -y
26
26
  ```
27
27
 
28
- This package is **NOT** restricted to use `Python 3.10` or `numpy 1.26` (as specified in the `requirements.txt`). Feel free to adjust at your convenience, just if the package works.
28
+ This package is **NOT** restricted to use `Python 3.12`. Feel free to adjust at your convenience, just if the package works.
29
29
 
30
- To install the pip package of the proposed algorithm (including the trajectory library built on it), and also the dependencies:
30
+ To install the pip package of the proposed algorithm (including the trajectory library built on it):
31
31
  ```bash
32
- $ pip install -r requirements.txt
33
32
  $ bash install.bash
34
33
  ```
34
+ or
35
+ ```bash
36
+ $ pip install mrarbgrad
37
+ ```
35
38
 
36
- It's the best practice to use my script `install.bash` for installation. You can also install via `pip install .` but remember to delete `*.egg-info` or pip will run into bug when uninstalling this package in current folder (see comments in `install.bash`).
39
+ You can also install via `pip install .` but remember to delete `*.egg-info` or pip will run into bug when uninstalling this package in current folder (see comments in `install.bash`).
37
40
 
38
41
  ## Examples & Usages
39
42
  Examples for generating gradient waveforms for either built-in trajectory (trajectory library) or external trajectory (expressed by trajectory function or trajectory samples) can be found in the `example` folder.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MRArbGrad
3
- Version: 2.0.1
3
+ Version: 2.1.0
4
4
  Summary: Gradient waveform design tool for arbitrary k-space trajectories.
5
5
  Author-email: Ryan <ryan_shanghaitech@proton.me>
6
6
  License-Expression: MIT
@@ -22,18 +22,21 @@ This toolbox is a pip package with C++ backend. The pip package can be called vi
22
22
  ```bash
23
23
  $ conda create -n magtest -y
24
24
  $ conda activate magtest
25
- $ conda install python==3.10 -y
25
+ $ conda install python==3.12 -y
26
26
  ```
27
27
 
28
- This package is **NOT** restricted to use `Python 3.10` or `numpy 1.26` (as specified in the `requirements.txt`). Feel free to adjust at your convenience, just if the package works.
28
+ This package is **NOT** restricted to use `Python 3.12`. Feel free to adjust at your convenience, just if the package works.
29
29
 
30
- To install the pip package of the proposed algorithm (including the trajectory library built on it), and also the dependencies:
30
+ To install the pip package of the proposed algorithm (including the trajectory library built on it):
31
31
  ```bash
32
- $ pip install -r requirements.txt
33
32
  $ bash install.bash
34
33
  ```
34
+ or
35
+ ```bash
36
+ $ pip install mrarbgrad
37
+ ```
35
38
 
36
- It's the best practice to use my script `install.bash` for installation. You can also install via `pip install .` but remember to delete `*.egg-info` or pip will run into bug when uninstalling this package in current folder (see comments in `install.bash`).
39
+ You can also install via `pip install .` but remember to delete `*.egg-info` or pip will run into bug when uninstalling this package in current folder (see comments in `install.bash`).
37
40
 
38
41
  ## Examples & Usages
39
42
  Examples for generating gradient waveforms for either built-in trajectory (trajectory library) or external trajectory (expressed by trajectory function or trajectory samples) can be found in the `example` folder.
@@ -8,18 +8,21 @@ This toolbox is a pip package with C++ backend. The pip package can be called vi
8
8
  ```bash
9
9
  $ conda create -n magtest -y
10
10
  $ conda activate magtest
11
- $ conda install python==3.10 -y
11
+ $ conda install python==3.12 -y
12
12
  ```
13
13
 
14
- This package is **NOT** restricted to use `Python 3.10` or `numpy 1.26` (as specified in the `requirements.txt`). Feel free to adjust at your convenience, just if the package works.
14
+ This package is **NOT** restricted to use `Python 3.12`. Feel free to adjust at your convenience, just if the package works.
15
15
 
16
- To install the pip package of the proposed algorithm (including the trajectory library built on it), and also the dependencies:
16
+ To install the pip package of the proposed algorithm (including the trajectory library built on it):
17
17
  ```bash
18
- $ pip install -r requirements.txt
19
18
  $ bash install.bash
20
19
  ```
20
+ or
21
+ ```bash
22
+ $ pip install mrarbgrad
23
+ ```
21
24
 
22
- It's the best practice to use my script `install.bash` for installation. You can also install via `pip install .` but remember to delete `*.egg-info` or pip will run into bug when uninstalling this package in current folder (see comments in `install.bash`).
25
+ You can also install via `pip install .` but remember to delete `*.egg-info` or pip will run into bug when uninstalling this package in current folder (see comments in `install.bash`).
23
26
 
24
27
  ## Examples & Usages
25
28
  Examples for generating gradient waveforms for either built-in trajectory (trajectory library) or external trajectory (expressed by trajectory function or trajectory samples) can be found in the `example` folder.
@@ -28,14 +28,16 @@ mag.setDbgPrint(1) # enable debug info (for benchmark purpose)
28
28
  # calculate gradient
29
29
  # lstArrK0, lstArrGrad = mag.getG_Spiral(is3D=0, **argCom); nAx = 2
30
30
  # lstArrK0, lstArrGrad = mag.getG_VarDenSpiral(is3D=0, **argCom); nAx = 2
31
- lstArrK0, lstArrGrad = mag.getG_VarDenSpiral_RT(is3D=0, **argCom); nAx = 2
32
- # lstArrK0, lstArrGrad = mag.getG_Rosette(is3D=0, **argCom); nAx = 2
31
+ # lstArrK0, lstArrGrad = mag.getG_VarDenSpiral_RT(is3D=0, **argCom); nAx = 2
32
+ lstArrK0, lstArrGrad = mag.getG_Rosette(is3D=0, **argCom); nAx = 2
33
33
  # lstArrK0, lstArrGrad = mag.getG_Rosette_Trad(**argCom); nAx = 2
34
34
  # lstArrK0, lstArrGrad = mag.getG_Shell3d(**argCom); nAx = 3
35
35
  # lstArrK0, lstArrGrad = mag.getG_Yarnball(**argCom); nAx = 3
36
36
  # lstArrK0, lstArrGrad = mag.getG_Seiffert(**argCom); nAx = 3
37
37
  # lstArrK0, lstArrGrad = mag.getG_Cones(**argCom); nAx = 3
38
38
 
39
+ # lstArrGrad = mag.gradClip(lstArrGrad, dtGrad, sLim, gLim) # clip slew/grad amp with hardware constraint
40
+
39
41
  print("")
40
42
  print(f"Intlea Num.: {len(lstArrGrad)}")
41
43
  nRO_Max = amax([arrG.shape[0] for arrG in lstArrGrad])
@@ -6,16 +6,16 @@ import mrarbgrad as mag
6
6
  gamma = 42.5756e6
7
7
  fov = 0.256
8
8
  nPix = 256
9
- dtGrad = 10e-6
10
- dtADC = 2.5e-6
9
+ dtGrad = 10e-6 * 1e-1
10
+ dtADC = 2.5e-6 * 1e-1
11
11
  sLim = 50 * gamma * fov/nPix
12
12
  gLim = 20e-3 * gamma * fov/nPix
13
13
  # gLim = 1/nPix/dtADC
14
14
 
15
15
  # Rosette
16
16
  nAx = 2
17
- om1 = 5*pi
18
- om2 = 3*pi
17
+ om1 = 19*pi
18
+ om2 = 17*pi
19
19
  def Rosette(t):
20
20
  rho = 0.5*sin(om1*t)
21
21
  return array\
@@ -28,13 +28,14 @@ def Rosette(t):
28
28
  pLim = [0,1]
29
29
 
30
30
  # derive slew-rate constrained trajectory
31
- arrG, _ = mag.calGrad4ExFunc(False, fov, nPix, sLim, gLim, dtGrad, Rosette, None, None, pLim[0], pLim[1])
32
- nRO, _ = arrG.shape
31
+ arrGrad = mag.calGrad4ExFunc(False, fov, nPix, sLim, gLim, dtGrad, Rosette, None, None, pLim[0], pLim[1])[0]
32
+ # arrGrad = mag.gradClip(arrGrad, dtGrad, sLim, gLim) # clip slew/grad amp with hardware constraint
33
+ nRO = arrGrad.shape[0]
33
34
 
34
- arrS = diff(arrG, axis=0)/dtGrad
35
- print(f"sMax: {max(norm(arrS,axis=-1))/(42.58e6)*(nPix/fov)}")
35
+ arrSlew = diff(arrGrad, axis=0)/dtGrad
36
+ print(f"sMax: {max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov)}")
36
37
 
37
- arrK, _ = mag.cvtGrad2Traj(arrG, dtGrad, dtADC, 0.5)
38
+ arrK = mag.cvtGrad2Traj(arrGrad, dtGrad, dtADC, 0.5)[0]
38
39
 
39
40
  # derive reference trajectory
40
41
  arrP_Ref = linspace(pLim[0], pLim[1], int(1e4))
@@ -57,21 +58,21 @@ title("k-Space")
57
58
 
58
59
  subplot(222)
59
60
  for iAx in range(nAx):
60
- plot(arrG[:,iAx]/(42.58e6)*(nPix/fov), ".-")
61
+ plot(arrGrad[:,iAx]/(42.58e6)*(nPix/fov), ".-")
61
62
  grid("on")
62
63
  title("Gradient")
63
64
 
64
65
  subplot(223, projection=None if nAx==2 else "3d")
65
- if nAx==2: plot(arrG[:,0], arrG[:,1], ".-")
66
- if nAx==3: plot(arrG[:,0], arrG[:,1], arrG[:,2], ".-")
66
+ if nAx==2: plot(arrGrad[:,0], arrGrad[:,1], ".-")
67
+ if nAx==3: plot(arrGrad[:,0], arrGrad[:,1], arrGrad[:,2], ".-")
67
68
  axis("equal")
68
69
  grid("on")
69
70
  title("g-Space")
70
71
 
71
72
  subplot(224)
72
- plot(norm(arrS,axis=-1)/(42.58e6)*(nPix/fov), ".-")
73
+ plot(norm(arrSlew,axis=-1)/(42.58e6)*(nPix/fov), ".-")
73
74
  ylim(sLim/(42.58e6)*(nPix/fov)*0.9, sLim/(42.58e6)*(nPix/fov)*1.1)
74
75
  grid("on")
75
- title(f"Slewrate, max:{max(norm(arrS,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
76
+ title(f"Slewrate, max:{max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
76
77
 
77
78
  show()
@@ -32,13 +32,14 @@ nAx = 2
32
32
 
33
33
  # derive slew-rate constrained trajectory
34
34
  for i in range(1):
35
- arrG, _ = mag.calGrad4ExSamp(False, fov, nPix, sLim, gLim, dtGrad, arrK)
36
- nRO, _ = arrG.shape
35
+ arrGrad = mag.calGrad4ExSamp(False, fov, nPix, sLim, gLim, dtGrad, arrK)[0]
36
+ # arrGrad = mag.gradClip(arrGrad, dtGrad, sLim, gLim) # clip slew/grad amp with hardware constraint
37
+ nRO = arrGrad.shape[0]
37
38
 
38
- arrS = diff(arrG, axis=0)/dtGrad
39
- print(f"sMax: {max(norm(arrS,axis=-1))/(42.58e6)*(nPix/fov)}")
39
+ arrSlew = diff(arrGrad, axis=0)/dtGrad
40
+ print(f"sMax: {max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov)}")
40
41
 
41
- arrK, _ = mag.cvtGrad2Traj(arrG, dtGrad, dtADC, 0.5)
42
+ arrK, _ = mag.cvtGrad2Traj(arrGrad, dtGrad, dtADC, 0.5)
42
43
  arrK += TrajFunc(pLim[0])
43
44
  print(f"Err: {norm(arrK[-1,:]-TrajFunc(pLim[1])):.1e}")
44
45
 
@@ -63,21 +64,21 @@ title("k-Space")
63
64
 
64
65
  subplot(222)
65
66
  for iAx in range(nAx):
66
- plot(arrG[:,iAx]/(42.58e6)*(nPix/fov), ".-")
67
+ plot(arrGrad[:,iAx]/(42.58e6)*(nPix/fov), ".-")
67
68
  grid("on")
68
69
  title("Gradient")
69
70
 
70
71
  subplot(223, projection=None if nAx==2 else "3d")
71
- if nAx==2: plot(arrG[:,0], arrG[:,1], ".-")
72
- if nAx==3: plot(arrG[:,0], arrG[:,1], arrG[:,2], ".-")
72
+ if nAx==2: plot(arrGrad[:,0], arrGrad[:,1], ".-")
73
+ if nAx==3: plot(arrGrad[:,0], arrGrad[:,1], arrGrad[:,2], ".-")
73
74
  axis("equal")
74
75
  grid("on")
75
76
  title("g-Space")
76
77
 
77
78
  subplot(224)
78
- plot(norm(arrS,axis=-1)/(42.58e6)*(nPix/fov), ".-")
79
+ plot(norm(arrSlew,axis=-1)/(42.58e6)*(nPix/fov), ".-")
79
80
  ylim(sLim/(42.58e6)*(nPix/fov)*0.9, sLim/(42.58e6)*(nPix/fov)*1.1)
80
81
  grid("on")
81
- title(f"Slewrate, max:{max(norm(arrS,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
82
+ title(f"Slewrate, max:{max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
82
83
 
83
84
  show()
@@ -24,13 +24,14 @@ arrK = Yarnball(arrP)
24
24
 
25
25
  # derive slew-rate constrained trajectory
26
26
  mag.setDbgPrint(1)
27
- arrG, _ = mag.calGrad4ExSamp(True, fov, nPix, sLim, gLim, dtGrad, arrK)
28
- nRO, _ = arrG.shape
27
+ arrGrad = mag.calGrad4ExSamp(True, fov, nPix, sLim, gLim, dtGrad, arrK)[0]
28
+ # arrGrad = mag.gradClip(arrGrad, dtGrad, sLim, gLim) # clip slew/grad amp with hardware constraint
29
+ nRO = arrGrad.shape[0]
29
30
 
30
- arrS = diff(arrG, axis=0)/dtGrad
31
- print(f"sMax: {max(norm(arrS,axis=-1))/(42.58e6)*(nPix/fov)}")
31
+ arrSlew = diff(arrGrad, axis=0)/dtGrad
32
+ print(f"sMax: {max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov)}")
32
33
 
33
- arrK, _ = mag.cvtGrad2Traj(arrG, dtGrad, dtADC, 0.5)
34
+ arrK, _ = mag.cvtGrad2Traj(arrGrad, dtGrad, dtADC, 0.5)
34
35
 
35
36
  # derive reference trajectory
36
37
  arrP_Ref = linspace(pLim[0], pLim[1], int(1e4))
@@ -51,21 +52,21 @@ title("k-Space")
51
52
 
52
53
  subplot(222)
53
54
  for iAx in range(nAx):
54
- plot(arrG[:,iAx]/(42.58e6)*(nPix/fov), ".-")
55
+ plot(arrGrad[:,iAx]/(42.58e6)*(nPix/fov), ".-")
55
56
  grid("on")
56
57
  title("Gradient")
57
58
 
58
59
  subplot(223, projection=None if nAx==2 else "3d")
59
- if nAx==2: plot(arrG[:,0], arrG[:,1], ".-")
60
- if nAx==3: plot(arrG[:,0], arrG[:,1], arrG[:,2], ".-")
60
+ if nAx==2: plot(arrGrad[:,0], arrGrad[:,1], ".-")
61
+ if nAx==3: plot(arrGrad[:,0], arrGrad[:,1], arrGrad[:,2], ".-")
61
62
  axis("equal")
62
63
  grid("on")
63
64
  title("g-Space")
64
65
 
65
66
  subplot(224)
66
- plot(norm(arrS,axis=-1)/(42.58e6)*(nPix/fov), ".-")
67
+ plot(norm(arrSlew,axis=-1)/(42.58e6)*(nPix/fov), ".-")
67
68
  ylim(sLim/(42.58e6)*(nPix/fov)*0.9, sLim/(42.58e6)*(nPix/fov)*1.1)
68
69
  grid("on")
69
- title(f"Slewrate, max:{max(norm(arrS,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
70
+ title(f"Slewrate, max:{max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
70
71
 
71
72
  show()
@@ -1,6 +1,6 @@
1
1
  from numpy import *
2
+ from numpy.linalg import norm
2
3
  from numpy.typing import *
3
- from matplotlib.pyplot import *
4
4
 
5
5
  goldrat = (1+sqrt(5))/2
6
6
  goldang = (2*pi)/(1+goldrat)
@@ -8,6 +8,46 @@ goldang = (2*pi)/(1+goldrat)
8
8
  getGoldrat = lambda: goldrat
9
9
  getGoldang = lambda: goldang
10
10
 
11
+ def gradClip(lstArrGrad:list[NDArray]|NDArray, dt:float, sLim:float, gLim:float) -> list[NDArray]|NDArray:
12
+ """
13
+ Clip the slewrate and gradient amlitude of a list of gradient waveforms
14
+
15
+ Args:
16
+ lstArrGrad: list of gradient waveforms
17
+ sLim: slewrate amplitude limit
18
+ gLim: gradient amplitude limit
19
+
20
+ Returns:
21
+ Clipped gradient waveforms
22
+ """
23
+ if isinstance(lstArrGrad, ndarray): _lstArrGrad = [lstArrGrad.copy()]
24
+ else: _lstArrGrad = lstArrGrad.copy()
25
+ nPE = len(_lstArrGrad)
26
+ for iPE in range(nPE):
27
+ # slew-rate clipping
28
+ arrGrad = _lstArrGrad[iPE]
29
+ arrSlew = diff(arrGrad, 1, 0)/dt
30
+ arrSlewNorm = norm(arrSlew, axis=-1)
31
+ arrSlewNorm[where(arrSlewNorm==0)] += 1e-6
32
+ arrSlewUnit = arrSlew/arrSlewNorm[:,newaxis]
33
+ clip(arrSlewNorm, None, sLim, out=arrSlewNorm)
34
+ arrSlew = arrSlewUnit*arrSlewNorm[:,newaxis]
35
+ # gradient clipping
36
+ arrGrad[:,:] = arrGrad[0,:]
37
+ arrGrad[1:,:] += cumsum(arrSlew*dt, axis=0)
38
+ arrGradNorm = norm(arrGrad, axis=-1)
39
+ arrGradNorm[where(arrGradNorm==0)] += 1e-6
40
+ arrGradUnit = arrGrad/arrGradNorm[:,newaxis]
41
+ clip(arrGradNorm, None, gLim, out=arrGradNorm)
42
+ arrGrad = arrGradUnit*arrGradNorm[:,newaxis]
43
+ #
44
+ _lstArrGrad[iPE] = arrGrad
45
+
46
+ if isinstance(lstArrGrad, ndarray):
47
+ return _lstArrGrad[0]
48
+ else:
49
+ return _lstArrGrad
50
+
11
51
  def rand3d(i:int|NDArray, nAx:int=3, kx=sqrt(2), ky=sqrt(3), kz=sqrt(7)) -> NDArray:
12
52
  return (hstack if size(i)==1 else vstack)\
13
53
  ([
@@ -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_VarDenSpiral, getG_VarDenSpiral_RT, getG_Yarnball
3
3
  from .Function import setSolverMtg, setTrajRev, setGoldAng, setShuf, setMaxG0, setMaxG1, setExGEnd, setMagOverSamp, setMagSFS, setMagGradRep, setMagTrajRep, setDbgPrint
4
- from .Utility import _calDiaphony, rotate, _calJacElip, _calCompElipInt, _calSphFibPt, cvtGrad2Traj, getGoldang, getGoldrat, rand3d
4
+ from .Utility import _calDiaphony, rotate, _calJacElip, _calCompElipInt, _calSphFibPt, cvtGrad2Traj, getGoldang, getGoldrat, rand3d, gradClip
5
5
 
6
6
  from . import trajfunc
@@ -12,7 +12,7 @@ bool gMag_enGradRep = true; // Gradient Reparameterization
12
12
  bool gMag_enTrajRep = true; // use trajectory reparameterization for MAG solver
13
13
  i64 gMag_nTrajSamp = 1000; // num. of samp. when doing Traj. Rep.
14
14
 
15
- MagSolver::MagSolver()
15
+ Mag::Mag()
16
16
  {
17
17
  m_dt = 10e-6; m_oversamp = 8;
18
18
  i64 nSampReserve = i64(100e-3/m_dt*m_oversamp); // reserve for 100ms
@@ -25,7 +25,7 @@ MagSolver::MagSolver()
25
25
  m_vv3G_For.reserve(nSampReserve);
26
26
  }
27
27
 
28
- bool MagSolver::setup
28
+ bool Mag::setup
29
29
  (
30
30
  TrajFunc* ptTraj,
31
31
  f64 sLim, f64 gLim,
@@ -61,7 +61,7 @@ bool MagSolver::setup
61
61
  return true;
62
62
  }
63
63
 
64
- bool MagSolver::setup
64
+ bool Mag::setup
65
65
  (
66
66
  const vv3& vv3TrajSamp,
67
67
  f64 sLim, f64 gLim,
@@ -81,10 +81,10 @@ bool MagSolver::setup
81
81
  return true;
82
82
  }
83
83
 
84
- MagSolver::~MagSolver()
84
+ Mag::~Mag()
85
85
  {}
86
86
 
87
- bool MagSolver::sovQDE(f64* psol0, f64* psol1, f64 a, f64 b, f64 c)
87
+ bool Mag::sovQDE(f64* psol0, f64* psol1, f64 a, f64 b, f64 c)
88
88
  {
89
89
  f64 delta = b*b - 4e0*a*c;
90
90
  if (psol0) *psol0 = (-b-(delta<0?0:std::sqrt(delta)))/(2*a);
@@ -92,7 +92,7 @@ bool MagSolver::sovQDE(f64* psol0, f64* psol1, f64 a, f64 b, f64 c)
92
92
  return delta>=0;
93
93
  }
94
94
 
95
- f64 MagSolver::getCurRad(f64 p)
95
+ f64 Mag::getCurRad(f64 p)
96
96
  {
97
97
  v3 dkdp; m_ptfTraj->getDkDp(&dkdp, p);
98
98
  v3 d2kdp2; m_ptfTraj->getD2kDp2(&d2kdp2, p);
@@ -103,7 +103,7 @@ f64 MagSolver::getCurRad(f64 p)
103
103
 
104
104
  #if 1
105
105
 
106
- f64 MagSolver::getDp(const v3& v3GPrev, const v3& v3GThis, f64 dt, f64 pPrev, f64 pThis, f64 signDp)
106
+ f64 Mag::getDp(const v3& v3GPrev, const v3& v3GThis, f64 dt, f64 pPrev, f64 pThis, f64 signDp)
107
107
  {
108
108
  // solve `ΔP` by RK2
109
109
  f64 l = v3::norm(v3GThis)*dt;
@@ -127,7 +127,7 @@ f64 MagSolver::getDp(const v3& v3GPrev, const v3& v3GThis, f64 dt, f64 pPrev, f6
127
127
 
128
128
  #else // less accurate due to estimation of PNext
129
129
 
130
- f64 MagSolver::getDp(const v3& v3GPrev, const v3& v3GThis, f64 dt, f64 pPrev, f64 pThis, f64 signDp)
130
+ f64 Mag::getDp(const v3& v3GPrev, const v3& v3GThis, f64 dt, f64 pPrev, f64 pThis, f64 signDp)
131
131
  {
132
132
  // solve `ΔP` by RK2
133
133
  f64 l = v3::norm(v3GThis)*dt;
@@ -140,7 +140,7 @@ f64 MagSolver::getDp(const v3& v3GPrev, const v3& v3GThis, f64 dt, f64 pPrev, f6
140
140
 
141
141
  #endif
142
142
 
143
- bool MagSolver::step(v3* gUnit, f64* gNormMin, f64* gNormMax, f64 p, f64 signDp, const v3& g, f64 sLim, f64 dt)
143
+ bool Mag::step(v3* gUnit, f64* gNormMin, f64* gNormMax, f64 p, f64 signDp, const v3& g, f64 sLim, f64 dt)
144
144
  {
145
145
  // current gradient direction
146
146
  v3 dkdp; m_ptfTraj->getDkDp(&dkdp, p);
@@ -161,7 +161,7 @@ bool MagSolver::step(v3* gUnit, f64* gNormMin, f64* gNormMax, f64 p, f64 signDp,
161
161
  return isQDESucc;
162
162
  }
163
163
 
164
- bool MagSolver::compute(vv3* pvv3G, vf64* pvf64P)
164
+ bool Mag::solve(vv3* pvv3G, vf64* pvf64P)
165
165
  {
166
166
  bool ret = true;
167
167
  f64 p0 = m_ptfTraj->getP0();
@@ -327,7 +327,7 @@ bool MagSolver::compute(vv3* pvv3G, vf64* pvf64P)
327
327
  return ret;
328
328
  }
329
329
 
330
- bool MagSolver::ramp_front(vv3* pvv3GRamp, const v3& g0, const v3& g0Des, f64 sLim, f64 dt)
330
+ bool Mag::ramp_front(vv3* pvv3GRamp, const v3& g0, const v3& g0Des, f64 sLim, f64 dt)
331
331
  {
332
332
  v3 dg = g0Des - g0;
333
333
  v3 dgUnit = v3::norm(dg)!=0 ? dg/v3::norm(dg) : v3(0,0,0);
@@ -347,7 +347,7 @@ bool MagSolver::ramp_front(vv3* pvv3GRamp, const v3& g0, const v3& g0Des, f64 sL
347
347
  return true;
348
348
  }
349
349
 
350
- f64 MagSolver::ramp_front(vv3* pvv3GRamp, const v3& g0, const v3& g0Des, i64 nSamp, f64 dt)
350
+ f64 Mag::ramp_front(vv3* pvv3GRamp, const v3& g0, const v3& g0Des, i64 nSamp, f64 dt)
351
351
  {
352
352
  v3 dg = g0Des - g0;
353
353
  v3 dgUnit = v3::norm(dg)!=0 ? dg/v3::norm(dg) : v3(0,0,0);
@@ -367,7 +367,7 @@ f64 MagSolver::ramp_front(vv3* pvv3GRamp, const v3& g0, const v3& g0Des, i64 nSa
367
367
  return sLim;
368
368
  }
369
369
 
370
- bool MagSolver::ramp_back(vv3* pvv3GRamp, const v3& g1, const v3& g1Des, f64 sLim, f64 dt)
370
+ bool Mag::ramp_back(vv3* pvv3GRamp, const v3& g1, const v3& g1Des, f64 sLim, f64 dt)
371
371
  {
372
372
  v3 dg = g1Des - g1;
373
373
  v3 dgUnit = v3::norm(dg)!=0 ? dg/v3::norm(dg) : v3(0,0,0);
@@ -387,7 +387,7 @@ bool MagSolver::ramp_back(vv3* pvv3GRamp, const v3& g1, const v3& g1Des, f64 sLi
387
387
  return true;
388
388
  }
389
389
 
390
- f64 MagSolver::ramp_back(vv3* pvv3GRamp, const v3& g1, const v3& g1Des, i64 nSamp, f64 dt)
390
+ f64 Mag::ramp_back(vv3* pvv3GRamp, const v3& g1, const v3& g1Des, i64 nSamp, f64 dt)
391
391
  {
392
392
  v3 dg = g1Des - g1;
393
393
  v3 dgUnit = v3::norm(dg)!=0 ? dg/v3::norm(dg) : v3(0,0,0);
@@ -407,7 +407,7 @@ f64 MagSolver::ramp_back(vv3* pvv3GRamp, const v3& g1, const v3& g1Des, i64 nSam
407
407
  return sLim;
408
408
  }
409
409
 
410
- bool MagSolver::revGrad(v3* pv3M0Dst, vv3* pvv3Dst, const v3& v3M0Src, const vv3& vv3Src, f64 dt)
410
+ bool Mag::revGrad(v3* pv3M0Dst, vv3* pvv3Dst, const v3& v3M0Src, const vv3& vv3Src, f64 dt)
411
411
  {
412
412
  bool ret = true;
413
413
 
@@ -426,7 +426,7 @@ bool MagSolver::revGrad(v3* pv3M0Dst, vv3* pvv3Dst, const v3& v3M0Src, const vv3
426
426
  return ret;
427
427
  }
428
428
 
429
- v3 MagSolver::calM0(const vv3& vv3G, f64 dt)
429
+ v3 Mag::calM0(const vv3& vv3G, f64 dt)
430
430
  {
431
431
  v3 M0 = v3(0,0,0);
432
432
  for (int64_t i = 1; i < (i64)vv3G.size(); ++i)
@@ -84,7 +84,7 @@ protected:
84
84
  SplineIntp m_intpX, m_intpY, m_intpZ;
85
85
  };
86
86
 
87
- class MagSolver
87
+ class Mag
88
88
  {
89
89
  public:
90
90
  typedef std::vector<i64> vi64;
@@ -97,7 +97,7 @@ public:
97
97
  typedef std::list<v3> lv3;
98
98
  typedef std::list<vv3> lvv3;
99
99
 
100
- MagSolver();
100
+ Mag();
101
101
  bool setup
102
102
  (
103
103
  TrajFunc* ptTraj,
@@ -112,8 +112,8 @@ public:
112
112
  f64 dt=10e-6, i64 oversamp=10,
113
113
  f64 dG0Norm=0e0, f64 dG1Norm=0e0
114
114
  );
115
- ~MagSolver();
116
- bool compute(vv3* plv3G, vf64* pvf64P=NULL);
115
+ ~Mag();
116
+ bool solve(vv3* plv3G, vf64* pvf64P=NULL);
117
117
  template <typename dtype, typename cv3>
118
118
  static bool decomp
119
119
  (
@@ -154,7 +154,7 @@ private:
154
154
 
155
155
  // definition must be in `.h` file (compiler limitation)
156
156
  template <typename dtype, typename cv3>
157
- bool MagSolver::decomp
157
+ bool Mag::decomp
158
158
  (
159
159
  std::vector<dtype>* pvfGx,
160
160
  std::vector<dtype>* pvfGy,
@@ -410,7 +410,7 @@ bool getG(MrTraj* pmt, vv3* pvv3M0PE, vvv3* pvvv3GRO)
410
410
  v3 v3M0PE; ret &= pmt->getM0PE(&v3M0PE, _i);
411
411
 
412
412
  // reverse gradient if needed
413
- if (gMain_enTrajRev) ret &= MagSolver::revGrad(&v3M0PE, &vv3GRO, v3M0PE, vv3GRO, dt);
413
+ if (gMain_enTrajRev) ret &= Mag::revGrad(&v3M0PE, &vv3GRO, v3M0PE, vv3GRO, dt);
414
414
 
415
415
  pvv3M0PE->at(i) = v3M0PE;
416
416
  pvvv3GRO->at(i) = vv3GRO;
@@ -58,7 +58,7 @@ public:
58
58
  m_sGradPara(m_sGradPara),
59
59
  m_nAcq(m_nAcq),
60
60
  m_nSampMax(m_nSampMax)
61
- { solver = MagSolver(); }
61
+ { mag = Mag(); }
62
62
 
63
63
  virtual ~MrTraj()
64
64
  {}
@@ -122,13 +122,13 @@ public:
122
122
  { vi64SeqIdx.push_back(i); }
123
123
 
124
124
  // decide step size, make step size and num of idx coprime
125
- i64 step = (i64)(num*(GOLDRAT-1));
126
- while (gcd(step, num)!=1)
127
- { ++step; }
125
+ i64 inc = (i64)(num*(GOLDRAT-1));
126
+ while (gcd(inc, num)!=1)
127
+ { ++inc; }
128
128
 
129
129
  // generate random index
130
130
  for(i64 i = 0; i < num; ++i)
131
- { pvi64Idx->push_back(i*step%num); }
131
+ { pvi64Idx->push_back(i*inc%num); }
132
132
 
133
133
  return true;
134
134
  }
@@ -167,7 +167,7 @@ protected:
167
167
  i64 m_nSampMax;
168
168
 
169
169
  // solver settings
170
- MagSolver solver;
170
+ Mag mag;
171
171
 
172
172
  // calculate required num. of rot. to satisfy Nyquist sampling (for spiral only)
173
173
  static i64 calNRot(f64 kRhoPhi, i64 nPix)
@@ -232,8 +232,8 @@ protected:
232
232
  const f64& gLim = sGradPara.gLim;
233
233
  const f64& dt = sGradPara.dt;
234
234
 
235
- solver.setup(&tf, sLim, gLim, dt, oversamp, gMrTraj_g0Norm, gMrTraj_g1Norm);
236
- ret &= solver.compute(pvv3G, pvf64P);
235
+ mag.setup(&tf, sLim, gLim, dt, oversamp, gMrTraj_g0Norm, gMrTraj_g1Norm);
236
+ ret &= mag.solve(pvv3G, pvf64P);
237
237
 
238
238
  return ret;
239
239
  }
@@ -245,8 +245,8 @@ protected:
245
245
  const f64& gLim = sGradPara.gLim;
246
246
  const f64& dt = sGradPara.dt;
247
247
 
248
- solver.setup(vv3TrajSamp, sLim, gLim, dt, oversamp, gMrTraj_g0Norm, gMrTraj_g1Norm);
249
- ret &= solver.compute(pvv3G, pvf64P);
248
+ mag.setup(vv3TrajSamp, sLim, gLim, dt, oversamp, gMrTraj_g0Norm, gMrTraj_g1Norm);
249
+ ret &= mag.solve(pvv3G, pvf64P);
250
250
 
251
251
  return ret;
252
252
  }
@@ -384,7 +384,7 @@ protected:
384
384
  {
385
385
  // add ramp gradient to satisfy desired Gstart and Gfinal
386
386
  vv3 vv3GRampFront;
387
- ret &= MagSolver::ramp_front(&vv3GRampFront, pvv3GRO->front(), v3(), sLim, dt);
387
+ ret &= Mag::ramp_front(&vv3GRampFront, pvv3GRO->front(), v3(), sLim, dt);
388
388
  pvv3GRO->insert(pvv3GRO->begin(), vv3GRampFront.begin(), vv3GRampFront.end());
389
389
 
390
390
  // corresponding parameter sequence
@@ -398,7 +398,7 @@ protected:
398
398
  {
399
399
  // add ramp gradient to satisfy desired Gstart and Gfinal
400
400
  vv3 vv3GRampBack;
401
- ret &= MagSolver::ramp_back(&vv3GRampBack, pvv3GRO->back(), v3(), sLim, dt);
401
+ ret &= Mag::ramp_back(&vv3GRampBack, pvv3GRO->back(), v3(), sLim, dt);
402
402
  pvv3GRO->insert(pvv3GRO->end(), vv3GRampBack.begin(), vv3GRampBack.end());
403
403
 
404
404
  // corresponding parameter sequence
@@ -2,7 +2,7 @@
2
2
 
3
3
  #include "../utility/global.h"
4
4
  #include "../utility/v3.h"
5
- // #include "../mag/MagSolver.h" // VS2010 reports error on this
5
+ // #include "../mag/Mag.h" // VS2010 reports error on this
6
6
 
7
7
  /*
8
8
  * Single trajectory define by a parameterized function getK()
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "MRArbGrad"
7
- version = "2.0.1"
7
+ version = "2.1.0"
8
8
  dependencies = ["numpy"]
9
9
 
10
10
  description = "Gradient waveform design tool for arbitrary k-space trajectories."
@@ -17,4 +17,4 @@ readme = "README.md"
17
17
 
18
18
  [project.urls]
19
19
  Repository = "https://github.com/RyanShanghaitech/MRArbGrad"
20
- Examples = "https://github.com/RyanShanghaitech/MRArbGrad/tree/main/example"
20
+ Examples = "https://github.com/RyanShanghaitech/MRArbGrad/tree/main/example"
File without changes
File without changes
File without changes
File without changes