MRArbGrad 4.4.0__tar.gz → 5.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/LICENSE +1 -1
  2. mrarbgrad-5.0.0/MANIFEST.in +1 -0
  3. mrarbgrad-5.0.0/MRArbGrad.egg-info/PKG-INFO +52 -0
  4. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/MRArbGrad.egg-info/SOURCES.txt +12 -16
  5. mrarbgrad-5.0.0/PKG-INFO +52 -0
  6. mrarbgrad-5.0.0/README.md +37 -0
  7. mrarbgrad-5.0.0/mrarbgrad_src/__init__.py +5 -0
  8. mrarbgrad-5.0.0/mrarbgrad_src/ext/mag/Mag.cpp +305 -0
  9. mrarbgrad-5.0.0/mrarbgrad_src/ext/mag/Mag.h +88 -0
  10. mrarbgrad-5.0.0/mrarbgrad_src/ext/main.cpp +372 -0
  11. mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/Cones.h +81 -0
  12. mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/Rosette.h +129 -0
  13. mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/ScanPlan.cpp +143 -0
  14. mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/ScanPlan.h +37 -0
  15. mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/Spiral.h +141 -0
  16. mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/SplineFunc.h +81 -0
  17. mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/TrajFunc.h +93 -0
  18. mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/Yarnball.h +78 -0
  19. {mrarbgrad-4.4.0/mrarbgrad_src/ext/traj → mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/future}/MrTraj_2D.h +2 -2
  20. {mrarbgrad-4.4.0/mrarbgrad_src/ext/traj → mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/future}/Seiffert.h +2 -2
  21. {mrarbgrad-4.4.0/mrarbgrad_src/ext/traj → mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/future}/Shell3d.h +3 -3
  22. {mrarbgrad-4.4.0/mrarbgrad_src/ext/traj → mrarbgrad-5.0.0/mrarbgrad_src/ext/traj/future}/Spiral.h +11 -11
  23. mrarbgrad-5.0.0/mrarbgrad_src/ext/utility/Intp.h +88 -0
  24. mrarbgrad-5.0.0/mrarbgrad_src/ext/utility/LinIntp.h +76 -0
  25. mrarbgrad-5.0.0/mrarbgrad_src/ext/utility/SplineIntp.h +137 -0
  26. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/mrarbgrad_src/ext/utility/global.h +2 -2
  27. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/mrarbgrad_src/ext/utility/v3.cpp +134 -111
  28. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/mrarbgrad_src/ext/utility/v3.h +22 -21
  29. mrarbgrad-5.0.0/mrarbgrad_src/main.py +119 -0
  30. mrarbgrad-5.0.0/mrarbgrad_src/trajfunc.py +206 -0
  31. mrarbgrad-5.0.0/mrarbgrad_src/utility.py +240 -0
  32. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/pyproject.toml +5 -4
  33. mrarbgrad-5.0.0/setup.py +27 -0
  34. mrarbgrad-4.4.0/MANIFEST.in +0 -1
  35. mrarbgrad-4.4.0/MRArbGrad.egg-info/PKG-INFO +0 -48
  36. mrarbgrad-4.4.0/PKG-INFO +0 -48
  37. mrarbgrad-4.4.0/README.md +0 -34
  38. mrarbgrad-4.4.0/example/example_BuiltInTraj.py +0 -105
  39. mrarbgrad-4.4.0/example/example_ExternalFunction2D.py +0 -80
  40. mrarbgrad-4.4.0/example/example_ExternalSamples2D.py +0 -84
  41. mrarbgrad-4.4.0/example/example_ExternalSamples3D.py +0 -72
  42. mrarbgrad-4.4.0/mrarbgrad_src/Function.py +0 -570
  43. mrarbgrad-4.4.0/mrarbgrad_src/Utility.py +0 -330
  44. mrarbgrad-4.4.0/mrarbgrad_src/__init__.py +0 -6
  45. mrarbgrad-4.4.0/mrarbgrad_src/ext/mag/Mag.cpp +0 -446
  46. mrarbgrad-4.4.0/mrarbgrad_src/ext/mag/Mag.h +0 -197
  47. mrarbgrad-4.4.0/mrarbgrad_src/ext/main.cpp +0 -871
  48. mrarbgrad-4.4.0/mrarbgrad_src/ext/traj/Cones.h +0 -141
  49. mrarbgrad-4.4.0/mrarbgrad_src/ext/traj/MrTraj.h +0 -414
  50. mrarbgrad-4.4.0/mrarbgrad_src/ext/traj/Rosette.h +0 -105
  51. mrarbgrad-4.4.0/mrarbgrad_src/ext/traj/TrajFunc.h +0 -90
  52. mrarbgrad-4.4.0/mrarbgrad_src/ext/traj/VDSpiral.h +0 -113
  53. mrarbgrad-4.4.0/mrarbgrad_src/ext/traj/Yarnball.h +0 -146
  54. mrarbgrad-4.4.0/mrarbgrad_src/ext/utility/Intp.h +0 -90
  55. mrarbgrad-4.4.0/mrarbgrad_src/ext/utility/LinIntp.h +0 -71
  56. mrarbgrad-4.4.0/mrarbgrad_src/ext/utility/SplineIntp.h +0 -134
  57. mrarbgrad-4.4.0/mrarbgrad_src/ext/utility/global.cpp +0 -1
  58. mrarbgrad-4.4.0/mrarbgrad_src/trajfunc/__init__.py +0 -1
  59. mrarbgrad-4.4.0/mrarbgrad_src/trajfunc/main.py +0 -38
  60. mrarbgrad-4.4.0/setup.py +0 -62
  61. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/MRArbGrad.egg-info/dependency_links.txt +0 -0
  62. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/MRArbGrad.egg-info/requires.txt +0 -0
  63. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/MRArbGrad.egg-info/top_level.txt +0 -0
  64. {mrarbgrad-4.4.0 → mrarbgrad-5.0.0}/setup.cfg +0 -0
@@ -1,4 +1,4 @@
1
- Copyright 2025 Rui Luo
1
+ Copyright 2026 Rui Luo
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
4
 
@@ -0,0 +1 @@
1
+ recursive-include mrarbgrad_src/ext/ *.cpp *.h
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: MRArbGrad
3
+ Version: 5.0.0
4
+ Summary: Gradient waveform design tool for arbitrary k-space trajectories.
5
+ Author-email: Rui <Rui.1002@proton.me>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/RyanShanghaitech/MRArbGrad
8
+ Project-URL: Examples, https://github.com/RyanShanghaitech/MRArbGrad/tree/main/example
9
+ Keywords: mri,pulse-sequence,gradient-waveform,trajectory,non-Cartesian,real-time
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: numpy
14
+ Dynamic: license-file
15
+
16
+ # Magnetic Resonance Arbitrary Gradient Toolbox (MRArbGrad)
17
+
18
+ Python library for solving gradient waveforms for arbitrary MRI trajectories. Trajectories can be specified as a Python function, or as a set of k-space points. A trajectory library is also provided. The underlying C/C++ code can be ported to compatible pulse sequence projects for fast gradient waveform design.
19
+
20
+ ## How to use
21
+ ### Install
22
+ ```bash
23
+ $ pip install mrarbgrad
24
+ ```
25
+
26
+ ### Import Libraries
27
+ ```python
28
+ from numpy import *
29
+ import mrarbgrad as mag
30
+ ```
31
+
32
+ ### Define Your Trajectory Function
33
+ ```python
34
+ def Rosette(t):
35
+ rho = 0.5 * sin(5*pi*t)
36
+ phi = 3*pi*t
37
+ return rho*array([cos(phi), sin(phi)])
38
+ ```
39
+
40
+ ### Solve for the Gradient Waveform
41
+ ```python
42
+ grad = mag.solve(Rosette, pmin=0, pmax=1)
43
+ ```
44
+ `pmin` and `pmax` define the bounds of function argument `t`. `grad[:,0]`, `grad[:,1]`, and `grad[:,2]` are the x-, y-, and z-axis gradient waveforms, respectively.
45
+
46
+ *For more usages such as specifying the hardware constraints, use of trajectory library and other utilities, please refer to [Examples](https://github.com/RyanShanghaitech/MRArbGrad/tree/main/example).*
47
+
48
+ ## Acknowledgements
49
+ The algorithm in this library is proposed in:
50
+
51
+ [1] Luo R, Huang H, Miao Q, Xu J, Hu P, Qi H. Real-Time Gradient Waveform Design for Arbitrary k-Space Trajectories. IEEE Transactions on Biomedical Engineering. 2026 Oct;73(10):3491-502. doi:10.1109/TBME.2026.3654117
52
+
@@ -5,39 +5,35 @@ pyproject.toml
5
5
  setup.py
6
6
  ./mrarbgrad_src/ext/main.cpp
7
7
  ./mrarbgrad_src/ext/mag/Mag.cpp
8
- ./mrarbgrad_src/ext/utility/global.cpp
8
+ ./mrarbgrad_src/ext/traj/ScanPlan.cpp
9
9
  ./mrarbgrad_src/ext/utility/v3.cpp
10
10
  MRArbGrad.egg-info/PKG-INFO
11
11
  MRArbGrad.egg-info/SOURCES.txt
12
12
  MRArbGrad.egg-info/dependency_links.txt
13
13
  MRArbGrad.egg-info/requires.txt
14
14
  MRArbGrad.egg-info/top_level.txt
15
- example/example_BuiltInTraj.py
16
- example/example_ExternalFunction2D.py
17
- example/example_ExternalSamples2D.py
18
- example/example_ExternalSamples3D.py
19
- mrarbgrad_src/Function.py
20
- mrarbgrad_src/Utility.py
21
15
  mrarbgrad_src/__init__.py
16
+ mrarbgrad_src/main.py
17
+ mrarbgrad_src/trajfunc.py
18
+ mrarbgrad_src/utility.py
22
19
  mrarbgrad_src/ext/main.cpp
23
20
  mrarbgrad_src/ext/mag/Mag.cpp
24
21
  mrarbgrad_src/ext/mag/Mag.h
25
22
  mrarbgrad_src/ext/traj/Cones.h
26
- mrarbgrad_src/ext/traj/MrTraj.h
27
- mrarbgrad_src/ext/traj/MrTraj_2D.h
28
23
  mrarbgrad_src/ext/traj/Rosette.h
29
- mrarbgrad_src/ext/traj/Seiffert.h
30
- mrarbgrad_src/ext/traj/Shell3d.h
24
+ mrarbgrad_src/ext/traj/ScanPlan.cpp
25
+ mrarbgrad_src/ext/traj/ScanPlan.h
31
26
  mrarbgrad_src/ext/traj/Spiral.h
27
+ mrarbgrad_src/ext/traj/SplineFunc.h
32
28
  mrarbgrad_src/ext/traj/TrajFunc.h
33
- mrarbgrad_src/ext/traj/VDSpiral.h
34
29
  mrarbgrad_src/ext/traj/Yarnball.h
30
+ mrarbgrad_src/ext/traj/future/MrTraj_2D.h
31
+ mrarbgrad_src/ext/traj/future/Seiffert.h
32
+ mrarbgrad_src/ext/traj/future/Shell3d.h
33
+ mrarbgrad_src/ext/traj/future/Spiral.h
35
34
  mrarbgrad_src/ext/utility/Intp.h
36
35
  mrarbgrad_src/ext/utility/LinIntp.h
37
36
  mrarbgrad_src/ext/utility/SplineIntp.h
38
- mrarbgrad_src/ext/utility/global.cpp
39
37
  mrarbgrad_src/ext/utility/global.h
40
38
  mrarbgrad_src/ext/utility/v3.cpp
41
- mrarbgrad_src/ext/utility/v3.h
42
- mrarbgrad_src/trajfunc/__init__.py
43
- mrarbgrad_src/trajfunc/main.py
39
+ mrarbgrad_src/ext/utility/v3.h
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: MRArbGrad
3
+ Version: 5.0.0
4
+ Summary: Gradient waveform design tool for arbitrary k-space trajectories.
5
+ Author-email: Rui <Rui.1002@proton.me>
6
+ License-Expression: MIT
7
+ Project-URL: Repository, https://github.com/RyanShanghaitech/MRArbGrad
8
+ Project-URL: Examples, https://github.com/RyanShanghaitech/MRArbGrad/tree/main/example
9
+ Keywords: mri,pulse-sequence,gradient-waveform,trajectory,non-Cartesian,real-time
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: numpy
14
+ Dynamic: license-file
15
+
16
+ # Magnetic Resonance Arbitrary Gradient Toolbox (MRArbGrad)
17
+
18
+ Python library for solving gradient waveforms for arbitrary MRI trajectories. Trajectories can be specified as a Python function, or as a set of k-space points. A trajectory library is also provided. The underlying C/C++ code can be ported to compatible pulse sequence projects for fast gradient waveform design.
19
+
20
+ ## How to use
21
+ ### Install
22
+ ```bash
23
+ $ pip install mrarbgrad
24
+ ```
25
+
26
+ ### Import Libraries
27
+ ```python
28
+ from numpy import *
29
+ import mrarbgrad as mag
30
+ ```
31
+
32
+ ### Define Your Trajectory Function
33
+ ```python
34
+ def Rosette(t):
35
+ rho = 0.5 * sin(5*pi*t)
36
+ phi = 3*pi*t
37
+ return rho*array([cos(phi), sin(phi)])
38
+ ```
39
+
40
+ ### Solve for the Gradient Waveform
41
+ ```python
42
+ grad = mag.solve(Rosette, pmin=0, pmax=1)
43
+ ```
44
+ `pmin` and `pmax` define the bounds of function argument `t`. `grad[:,0]`, `grad[:,1]`, and `grad[:,2]` are the x-, y-, and z-axis gradient waveforms, respectively.
45
+
46
+ *For more usages such as specifying the hardware constraints, use of trajectory library and other utilities, please refer to [Examples](https://github.com/RyanShanghaitech/MRArbGrad/tree/main/example).*
47
+
48
+ ## Acknowledgements
49
+ The algorithm in this library is proposed in:
50
+
51
+ [1] Luo R, Huang H, Miao Q, Xu J, Hu P, Qi H. Real-Time Gradient Waveform Design for Arbitrary k-Space Trajectories. IEEE Transactions on Biomedical Engineering. 2026 Oct;73(10):3491-502. doi:10.1109/TBME.2026.3654117
52
+
@@ -0,0 +1,37 @@
1
+ # Magnetic Resonance Arbitrary Gradient Toolbox (MRArbGrad)
2
+
3
+ Python library for solving gradient waveforms for arbitrary MRI trajectories. Trajectories can be specified as a Python function, or as a set of k-space points. A trajectory library is also provided. The underlying C/C++ code can be ported to compatible pulse sequence projects for fast gradient waveform design.
4
+
5
+ ## How to use
6
+ ### Install
7
+ ```bash
8
+ $ pip install mrarbgrad
9
+ ```
10
+
11
+ ### Import Libraries
12
+ ```python
13
+ from numpy import *
14
+ import mrarbgrad as mag
15
+ ```
16
+
17
+ ### Define Your Trajectory Function
18
+ ```python
19
+ def Rosette(t):
20
+ rho = 0.5 * sin(5*pi*t)
21
+ phi = 3*pi*t
22
+ return rho*array([cos(phi), sin(phi)])
23
+ ```
24
+
25
+ ### Solve for the Gradient Waveform
26
+ ```python
27
+ grad = mag.solve(Rosette, pmin=0, pmax=1)
28
+ ```
29
+ `pmin` and `pmax` define the bounds of function argument `t`. `grad[:,0]`, `grad[:,1]`, and `grad[:,2]` are the x-, y-, and z-axis gradient waveforms, respectively.
30
+
31
+ *For more usages such as specifying the hardware constraints, use of trajectory library and other utilities, please refer to [Examples](https://github.com/RyanShanghaitech/MRArbGrad/tree/main/example).*
32
+
33
+ ## Acknowledgements
34
+ The algorithm in this library is proposed in:
35
+
36
+ [1] Luo R, Huang H, Miao Q, Xu J, Hu P, Qi H. Real-Time Gradient Waveform Design for Arbitrary k-Space Trajectories. IEEE Transactions on Biomedical Engineering. 2026 Oct;73(10):3491-502. doi:10.1109/TBME.2026.3654117
37
+
@@ -0,0 +1,5 @@
1
+ from .main import solve, scan, config, saveF64, loadF64, saveF32, loadF32
2
+ from .utility import getGoldAng, getGoldRat, tm2hzpx, hzpx2tm, getK_Cartesian, getK_Radial, clip, integrate, delay, rotate
3
+ from .trajfunc import VDSpiral, Spiral, DDSpiral, Rosette, Yarnball, Cones
4
+
5
+ config() # use default settings
@@ -0,0 +1,305 @@
1
+ #include <cassert>
2
+ #include <algorithm>
3
+ #include <cstdio>
4
+ #include "../utility/global.h"
5
+ #include "Mag.h"
6
+
7
+ f64 Mag::dt = 10e-6; i64 Mag::ovsp = 4; // raster time, oversamp ratio
8
+ f64 Mag::sLim = 50 * 42.5756e6 * 1e-3; // slew. limit (Hz/px/s)
9
+ f64 Mag::gLim = 30e-3 * 42.5756e6 * 1e-3; // grad. limit (Hz/px)
10
+ f64 Mag::g0Norm = 0.0, Mag::g1Norm = 0.0; // start and stop grad. amp.
11
+ bool Mag::enTrajRep = true; // trajectory reparameterization
12
+ bool Mag::enGradRep = true; // gradient reparameterization
13
+ i64 Mag::lenTrajRsv = int(1e4), Mag::lenGradRsv = int(1e5);
14
+
15
+ Mag::Mag()
16
+ {
17
+ // for solver
18
+ this->paraBwd.reserve(Mag::lenGradRsv);
19
+ this->gradBwd.reserve(Mag::lenGradRsv);
20
+ this->gradBwdNorm.reserve(Mag::lenGradRsv);
21
+
22
+ this->paraFwd.reserve(Mag::lenGradRsv);
23
+ this->gradFwd.reserve(Mag::lenGradRsv);
24
+
25
+ this->para.reserve(Mag::lenGradRsv/Mag::ovsp);
26
+ this->grad.reserve(Mag::lenGradRsv/Mag::ovsp);
27
+
28
+ this->intp.init(Mag::lenGradRsv);
29
+ this->intp.eSearchMode = Intp::ECached;
30
+
31
+ // for trajectory reparameterization
32
+ this->trajSamp.resize(Mag::lenTrajRsv);
33
+ }
34
+
35
+ bool Mag::setTraj(const TrajFunc& func)
36
+ {
37
+ bool ret = true;
38
+ if (Mag::enTrajRep)
39
+ {
40
+ f64 p0 = func.getP0();
41
+ f64 p1 = func.getP1();
42
+ i64 n = this->trajSamp.size();
43
+ for (i64 i = 0; i < n; ++i)
44
+ {
45
+ f64 p = p0 + (p1-p0) * (i)/f64(n-1);
46
+ ret &= func.getK(&this->trajSamp[i], p);
47
+ }
48
+ this->spTrajFunc = SplineFunc(this->trajSamp);
49
+ this->trajFuncPtr = &this->spTrajFunc;
50
+ }
51
+ else
52
+ {
53
+ this->trajFuncPtr = &func;
54
+ }
55
+
56
+ return ret;
57
+ }
58
+
59
+ bool Mag::setTraj(const vv3& samp)
60
+ {
61
+ this->spTrajFunc = SplineFunc(samp);
62
+ this->trajFuncPtr = &this->spTrajFunc;
63
+
64
+ return true;
65
+ }
66
+
67
+ bool Mag::sovQDE(f64* x0, f64* x1, f64 a, f64 b, f64 c)
68
+ {
69
+ f64 delta = b*b - 4e0*a*c;
70
+ if (x0) *x0 = (-b-(delta<0?0:std::sqrt(delta)))/(2*a);
71
+ if (x1) *x1 = (-b+(delta<0?0:std::sqrt(delta)))/(2*a);
72
+ return delta>=0;
73
+ }
74
+
75
+ f64 Mag::curvature(f64 p)
76
+ {
77
+ #define EPS (1e-15)
78
+ v3 dkdp; this->trajFuncPtr->getDkDp(&dkdp, p);
79
+ v3 d2kdp2; this->trajFuncPtr->getD2kDp2(&d2kdp2, p);
80
+ f64 nume = v3::norm(v3::cross(dkdp, d2kdp2));
81
+ f64 deno = pow(v3::norm(dkdp), 3e0);
82
+ if (nume<EPS) nume = EPS;
83
+ if (deno<EPS) deno = EPS;
84
+ return nume/deno;
85
+ #undef EPS
86
+ }
87
+
88
+ #if 1
89
+
90
+ f64 Mag::getDp(const v3& gPrev, const v3& gThis, f64 dt, f64 pPrev, f64 pThis, f64 signDp)
91
+ {
92
+ // solve `ΔP` by RK2
93
+ f64 l = v3::norm(gThis)*dt;
94
+ // k1
95
+ f64 k1;
96
+ {
97
+ v3 dkdp; this->trajFuncPtr->getDkDp(&dkdp, pThis);
98
+ f64 dldp = v3::norm(dkdp)*signDp;
99
+ k1 = 1e0/dldp;
100
+ }
101
+ // k2
102
+ f64 k2;
103
+ {
104
+ v3 dkdp; this->trajFuncPtr->getDkDp(&dkdp, pThis+k1*l);
105
+ f64 dldp = v3::norm(dkdp)*signDp;
106
+ k2 = 1e0/dldp;
107
+ }
108
+ f64 dp = l*(0.5*k1 + 0.5*k2);
109
+ return dp;
110
+ }
111
+
112
+ #else // less accurate due to estimation of PNext
113
+
114
+ f64 Mag::getDp(const v3& v3GPrev, const v3& v3GThis, f64 dt, f64 pPrev, f64 pThis, f64 signDp)
115
+ {
116
+ // solve `ΔP` by RK2
117
+ f64 l = v3::norm(v3GThis)*dt;
118
+ v3 dkdp0; ptfTraj->getDkDp(&dkdp0, pThis);
119
+ v3 dkdp1; ptfTraj->getDkDp(&dkdp1, pThis*2e0-pPrev);
120
+ f64 dldp0 = v3::norm(dkdp0)*signDp;
121
+ f64 dldp1 = v3::norm(dkdp1)*signDp;
122
+ return l*(1e0/dldp0 + 1e0/dldp1)/2e0;
123
+ }
124
+
125
+ #endif
126
+
127
+ bool Mag::step(v3* gUnit, f64* gNormMin, f64* gNormMax, f64 p, f64 signDp, const v3& g, f64 sLim, f64 dt)
128
+ {
129
+ // current gradient direction
130
+ v3 dkdp; this->trajFuncPtr->getDkDp(&dkdp, p);
131
+ f64 dldp = v3::norm(dkdp)*signDp;
132
+ if (gUnit) *gUnit = dkdp/dldp;
133
+
134
+ // current gradient magnitude
135
+ bool isQDESucc = sovQDE
136
+ (
137
+ gNormMin, gNormMax,
138
+ 1e0,
139
+ -2e0*v3::inner(g, *gUnit),
140
+ v3::inner(g, g) - std::pow(sLim*dt, 2e0)
141
+ );
142
+ if (gNormMin) *gNormMin = fabs(*gNormMin);
143
+ if (gNormMax) *gNormMax = fabs(*gNormMax);
144
+
145
+ return isQDESucc;
146
+ }
147
+
148
+ bool Mag::solve(vv3* grad, vf64* para)
149
+ {
150
+ bool ret = true;
151
+ f64 p0 = this->trajFuncPtr->getP0();
152
+ f64 p1 = this->trajFuncPtr->getP1();
153
+ f64 tStep = Mag::dt / Mag::ovsp;
154
+ bool isQDESucc = true; (void)isQDESucc;
155
+
156
+ // backward
157
+ v3 g1Unit; ret &= this->trajFuncPtr->getDkDp(&g1Unit, p1);
158
+ g1Unit = g1Unit * (p0>p1?1e0:-1e0);
159
+ g1Unit = g1Unit / v3::norm(g1Unit);
160
+ f64 g1Norm = Mag::g1Norm;
161
+ g1Norm = std::min(g1Norm, Mag::gLim);
162
+ g1Norm = std::min(g1Norm, std::sqrt(Mag::sLim/curvature(p1)));
163
+ v3 g1 = g1Unit * g1Norm;
164
+
165
+ this->paraBwd.clear(); this->paraBwd.push_back(p1);
166
+ this->gradBwd.clear(); this->gradBwd.push_back(g1);
167
+ this->gradBwdNorm.clear(); this->gradBwdNorm.push_back(v3::norm(g1));
168
+ while (1)
169
+ {
170
+ f64 p = this->paraBwd.back();
171
+ v3 g = this->gradBwd.back();
172
+
173
+ // update grad
174
+ v3 gUnit; f64 gNorm;
175
+ isQDESucc = step(&gUnit, NULL, &gNorm, p, (p0-p1)/fabs(p0-p1), g, Mag::sLim, tStep);
176
+ gNorm = std::min(gNorm, Mag::gLim);
177
+ gNorm = std::min(gNorm, std::sqrt(Mag::sLim/curvature(p)));
178
+ g = gUnit*gNorm;
179
+
180
+ // update para
181
+ p += getDp(this->gradBwd.back(), g, tStep, this->paraBwd.back(), p, (p0-p1)/fabs(p0-p1));
182
+
183
+ // stop or append
184
+ if (fabs(p - p1) >= (1-1e-6)*fabs(p0 - p1))
185
+ {
186
+ // printf("bac: dP/dP1 = %lf/%lf\n", dP, dP1); // test
187
+ break;
188
+ }
189
+ else
190
+ {
191
+ // printf("bac: dP = %lf\n", dP); // test
192
+ this->paraBwd.push_back(p);
193
+ this->gradBwd.push_back(g);
194
+ this->gradBwdNorm.push_back(v3::norm(g));
195
+ }
196
+ }
197
+
198
+ std::reverse(this->paraBwd.begin(), this->paraBwd.end());
199
+ std::reverse(this->gradBwdNorm.begin(), this->gradBwdNorm.end());
200
+
201
+ this->intp.fit(this->paraBwd, this->gradBwdNorm);
202
+
203
+ // forward
204
+ v3 g0Unit; ret &= this->trajFuncPtr->getDkDp(&g0Unit, p0);
205
+ g0Unit = g0Unit * (p1>p0?1e0:-1e0);
206
+ g0Unit = g0Unit / v3::norm(g0Unit);
207
+ f64 g0Norm = Mag::g0Norm;
208
+ g0Norm = std::min(g0Norm, Mag::gLim);
209
+ g0Norm = std::min(g0Norm, std::sqrt(Mag::sLim/curvature(p0)));
210
+ g0Norm = std::min(g0Norm, this->intp.eval(p0));
211
+ v3 g0 = g0Unit * g0Norm;
212
+
213
+ this->paraFwd.clear(); this->paraFwd.push_back(p0);
214
+ this->gradFwd.clear(); this->gradFwd.push_back(g0);
215
+ while (1)
216
+ {
217
+ f64 p = this->paraFwd.back();
218
+ v3 g = this->gradFwd.back();
219
+
220
+ // update grad
221
+ v3 gUnit; f64 gNorm;
222
+ isQDESucc = step(&gUnit, NULL, &gNorm, p, (p1-p0)/fabs(p1-p0), g, Mag::sLim, tStep);
223
+
224
+ f64 gNormBwd = this->intp.eval(p);
225
+ gNorm = std::min(gNorm, gNormBwd);
226
+ g = gUnit*gNorm;
227
+
228
+ // update para
229
+ p += getDp(this->gradFwd.back(), g, tStep, this->paraFwd.back(), p, (p1-p0)/fabs(p1-p0));
230
+
231
+ // stop or append
232
+ if (fabs(p - p0) >= (1-1e-6)*fabs(p1 - p0)) // || dGNorm <= 0)
233
+ {
234
+ // printf("for: dP/dP1 = %lf/%lf\n", dP, dP1); // test
235
+ break;
236
+ }
237
+ else
238
+ {
239
+ // printf("for: dP = %lf\n", dP); // test
240
+ this->paraFwd.push_back(p);
241
+ this->gradFwd.push_back(g);
242
+ }
243
+ }
244
+
245
+ // deoversamp the para. vec.
246
+ if (!para) para = &this->para;
247
+ if (!grad) grad = &this->grad;
248
+ {
249
+ i64 n = this->paraFwd.size();
250
+ para->clear(); para->reserve(n/Mag::ovsp+1);
251
+ grad->clear(); grad->reserve(n/Mag::ovsp+1);
252
+ for (i64 i = 0; i < n; ++i)
253
+ {
254
+ if (i%Mag::ovsp==Mag::ovsp/2)
255
+ {
256
+ para->push_back(this->paraFwd[i]);
257
+ grad->push_back(this->gradFwd[i]);
258
+ }
259
+ }
260
+ }
261
+
262
+ // derive gradient
263
+ if (Mag::enGradRep)
264
+ {
265
+ v3 k1, k0;
266
+ vf64::iterator ivf64P = std::next(para->begin());
267
+ vf64::iterator ivf64PPrev = para->begin();
268
+ i64 n = para->size();
269
+ grad->clear();
270
+ for (i64 i = 1; i < n; ++i)
271
+ {
272
+ ret &= this->trajFuncPtr->getK(&k1, *ivf64P);
273
+ ret &= this->trajFuncPtr->getK(&k0, *ivf64PPrev);
274
+ grad->push_back((k1 - k0)/Mag::dt);
275
+ *ivf64PPrev = *ivf64P; // ensure the consistent length
276
+ ++ivf64P, ++ivf64PPrev;
277
+ }
278
+ para->resize(n-1);
279
+ }
280
+
281
+ // extrapolate
282
+ i64 nExtp; vv3 piece;
283
+
284
+ nExtp = (i64)std::ceil(v3::norm(grad->front() - g0) / (Mag::sLim*Mag::dt));
285
+ piece = v3::linspace(g0, grad->front(), nExtp, false);
286
+ grad->insert(grad->begin(), piece.begin(), piece.end());
287
+ para->insert(para->begin(), nExtp, para->front());
288
+
289
+ nExtp = (i64)std::ceil(v3::norm(grad->back() - g1) / (Mag::sLim*Mag::dt));
290
+ piece = v3::linspace(g1, grad->back(), nExtp, false);
291
+ grad->insert(grad->end(), piece.rbegin(), piece.rend());
292
+ para->insert(para->end(), nExtp, para->back());
293
+
294
+ return ret;
295
+ }
296
+
297
+ v3 Mag::calM0(const vv3& grad, f64 dt)
298
+ {
299
+ v3 m0 = v3(0,0,0);
300
+ for (int64_t i = 1; i < (i64)grad.size(); ++i)
301
+ { m0 += (grad[i] + grad[i-1]) * dt/2e0; }
302
+
303
+ return m0;
304
+ }
305
+
@@ -0,0 +1,88 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+ #include <list>
5
+ #include <tuple>
6
+ #include <cmath>
7
+ #include <stdexcept>
8
+ #include <algorithm>
9
+ #include "../utility/global.h"
10
+ #include "../utility/v3.h"
11
+ #include "../traj/TrajFunc.h"
12
+ #include "../traj/SplineFunc.h"
13
+ #include "../utility/LinIntp.h"
14
+
15
+ class Mag
16
+ {
17
+ public:
18
+ static f64 dt; static i64 ovsp;
19
+ static f64 sLim, gLim, g0Norm, g1Norm;
20
+ static bool enTrajRep, enGradRep;
21
+ static i64 lenTrajRsv, lenGradRsv;
22
+
23
+ Mag();
24
+ bool setTraj(const TrajFunc& func);
25
+ bool setTraj(const vv3& samp);
26
+ bool solve(vv3* grad, vf64* para=NULL);
27
+ template <typename dtype, typename xv3>
28
+ static bool decomp
29
+ (
30
+ std::vector<dtype>* gx,
31
+ std::vector<dtype>* gy,
32
+ std::vector<dtype>* gz,
33
+ const xv3& grad
34
+ );
35
+ static v3 calM0(const vv3& grad, f64 dt);
36
+
37
+ private:
38
+ // reserved vector for faster computation
39
+ SplineFunc spTrajFunc;
40
+ const TrajFunc* trajFuncPtr;
41
+ vv3 trajSamp;
42
+
43
+ vf64 paraBwd;
44
+ vv3 gradBwd;
45
+ vf64 gradBwdNorm;
46
+ vf64 paraFwd;
47
+ vv3 gradFwd;
48
+ vf64 para;
49
+ vv3 grad;
50
+
51
+ LinIntp intp;
52
+
53
+ f64 curvature(f64 p);
54
+ f64 getDp(const v3& gPrev, const v3& gThis, f64 dt, f64 pPrev, f64 pThis, f64 signDp);
55
+ bool step(v3* gUnit, f64* gNormMin, f64* gNormMax, f64 p, f64 signDp, const v3& g, f64 sLim, f64 dt);
56
+ static bool sovQDE(f64* x0, f64* x1, f64 a, f64 b, f64 c);
57
+ };
58
+
59
+ // definition must be in `.h` file (compiler limitation)
60
+ template <typename dtype, typename xv3>
61
+ bool Mag::decomp
62
+ (
63
+ std::vector<dtype>* pGx,
64
+ std::vector<dtype>* pGy,
65
+ std::vector<dtype>* pGz,
66
+ const xv3& grad
67
+ )
68
+ {
69
+ bool ret = true;
70
+
71
+ std::fill(pGx->begin(), pGx->end(), (dtype)0);
72
+ std::fill(pGy->begin(), pGy->end(), (dtype)0);
73
+ std::fill(pGz->begin(), pGz->end(), (dtype)0);
74
+
75
+ typename std::vector<dtype>::iterator iGx = pGx->begin();
76
+ typename std::vector<dtype>::iterator iGy = pGy->begin();
77
+ typename std::vector<dtype>::iterator iGz = pGz->begin();
78
+ typename xv3::const_iterator iGrad = grad.begin();
79
+ while (iGrad != grad.end())
80
+ {
81
+ *(iGx++) = dtype(iGrad->x);
82
+ *(iGy++) = dtype(iGrad->y);
83
+ *(iGz++) = dtype(iGrad->z);
84
+ ++iGrad;
85
+ }
86
+ return ret;
87
+ }
88
+