ucla-geotech-tools 1.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.
@@ -0,0 +1,7 @@
1
+ Copyright 2023 Scott J. Brandenberg
2
+
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
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,99 @@
1
+ Metadata-Version: 2.1
2
+ Name: ucla_geotech_tools
3
+ Version: 1.0.0
4
+ Summary: A collection of software tools developed by the UCLA geotechnical group
5
+ License: LICENSE.txt
6
+ Author: Scott J. Brandenberg
7
+ Requires-Python: >=3.8,<4.0
8
+ Classifier: License :: Other/Proprietary License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.8
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Dist: numpy (>=1.22,<2.0)
16
+ Requires-Dist: scipy (>=1.8,<2.0)
17
+ Description-Content-Type: text/markdown
18
+
19
+ # auto_fchp
20
+
21
+ Return the high-pass corner frequency value that stabilizes the displacement of a ground motion record.
22
+
23
+ The high-pass corner frequency, fchp, is selected to satisfy two objectives:
24
+ 1. A polynomial is fit to the filtered displacement record, and the amplitude of the polynomial fit
25
+ divided by the amplitude of the filtered displacement record is within a tolerance of a specified target.
26
+ 2. The amplitude of the initial portion of the displacement record before the p-wave arrival divided by
27
+ the amplitude of the filtered displacement record is within a tolerance of a specified target.
28
+
29
+ The value of fchp is computed numerically using the Scipy package optimize.ridder(). Two initial values
30
+ of fchp are provided that bracket the root, and the Scipy package solves for the root that minimizes the
31
+ objective function. The tolerance is on the value of fchp (i.e., xtol in optimize.ridder)
32
+
33
+ A value of fchp is obtained first to satisfy objective 1. Objective 2 is optional, and if it is applied,
34
+ the value of fchp from objective 1 is checked against objective 2. If the residual from objective 2 is
35
+ less than or equal to zero, fchp is set equal to the value from objective 1. Otherwise, iterations are
36
+ performed to satisfy objective 2.
37
+
38
+ ## Installation
39
+ ```python
40
+ pip install ucla_geotech_tools.auto_fchp
41
+ ```
42
+
43
+ ## Functions
44
+ ```python
45
+ get_fchp_sp(dt, acc, **kwargs)
46
+ """Args:
47
+ dt (float): time step in seconds
48
+ acc (numpy array, dtype=float): acceleration array in L/s/s, where L is length (e.g., meters)
49
+
50
+ Keyword Args:
51
+ target: desired ratio of polynomial fit amplitude to displacement amplitude (default=0.02)
52
+ tol: tolerance for fchp (default=0.001)
53
+ poly_order: order of polynomial to fit to filtered displacement record (default=6)
54
+ maxiter: maximum number of iterations (default=30)
55
+ fchp_min: minimum frequency in Hz to consider for fchp (default=0.001)
56
+ fchp_max: maximum frequency in Hz to consider for fchp (default=0.5)
57
+ tukey_alpha: alpha parameter for scipy.signal.windows.tukey (default=0.05)
58
+ apply_disp_ratio: flag to indicate whether to apply objective 2 (default=0)
59
+ disp_ratio_time: duration in seconds of the initial portion of the record before the p-wave arrival (default=30)
60
+ disp_ratio_target: target ratio of amplitude of initial portion of displacement record to amplitude of displacement record
61
+ """
62
+ get_residual1(fchp, *args):
63
+ """Return the residual defined as disp_fit/disp_filt - target.
64
+
65
+ Args:
66
+ fchp = High-pass corner frequency
67
+ Fdisp = Numpy array containing Fourier coefficients of displacement record
68
+ time = Numpy array containing time values
69
+ poly_order = Order of polynomial to fit to filtered displacement
70
+ target = Desired ratio of polynomial fit amplitude to displacement signal amplitude
71
+ freq = Numpy array containing frequency values
72
+
73
+ Computed variables:
74
+ filt = Coefficients of 5th order Butterworth filter
75
+ Fdisp_filt = Numpy array containing Fourier coefficients of filtered displacement record
76
+ disp_filt = Numpy array containing filtered displacement record
77
+ coef = Coefficients of polynomial fit to displacement record
78
+ disp_fit = Numpy array containing polynomial fit ordinates at each time
79
+ """
80
+
81
+
82
+ get_residual2(fchp, *args):
83
+ """Return the residual defined as disp_init/disp - target.
84
+
85
+ Args:
86
+ fchp = High-pass corner frequency
87
+ Fdisp = Numpy array containing Fourier coefficients of displacement record
88
+ time = Numpy array containing time values
89
+ disp_time = Duration of initial portion of record before p-wave arrival
90
+ disp_target = Desired ratio of amplitude of initial portion of displacement record to amplitude of displacement record
91
+ freq = Numpy array containing frequency values
92
+
93
+ Computed variables:
94
+ filt = Coefficients of 5th order Butterworth filter
95
+ Fdisp_filt = Numpy array containing Fourier coefficients of filtered displacement record
96
+ disp_filt = Numpy array containing filtered displacement record
97
+ """
98
+ ```
99
+
@@ -0,0 +1,80 @@
1
+ # auto_fchp
2
+
3
+ Return the high-pass corner frequency value that stabilizes the displacement of a ground motion record.
4
+
5
+ The high-pass corner frequency, fchp, is selected to satisfy two objectives:
6
+ 1. A polynomial is fit to the filtered displacement record, and the amplitude of the polynomial fit
7
+ divided by the amplitude of the filtered displacement record is within a tolerance of a specified target.
8
+ 2. The amplitude of the initial portion of the displacement record before the p-wave arrival divided by
9
+ the amplitude of the filtered displacement record is within a tolerance of a specified target.
10
+
11
+ The value of fchp is computed numerically using the Scipy package optimize.ridder(). Two initial values
12
+ of fchp are provided that bracket the root, and the Scipy package solves for the root that minimizes the
13
+ objective function. The tolerance is on the value of fchp (i.e., xtol in optimize.ridder)
14
+
15
+ A value of fchp is obtained first to satisfy objective 1. Objective 2 is optional, and if it is applied,
16
+ the value of fchp from objective 1 is checked against objective 2. If the residual from objective 2 is
17
+ less than or equal to zero, fchp is set equal to the value from objective 1. Otherwise, iterations are
18
+ performed to satisfy objective 2.
19
+
20
+ ## Installation
21
+ ```python
22
+ pip install ucla_geotech_tools.auto_fchp
23
+ ```
24
+
25
+ ## Functions
26
+ ```python
27
+ get_fchp_sp(dt, acc, **kwargs)
28
+ """Args:
29
+ dt (float): time step in seconds
30
+ acc (numpy array, dtype=float): acceleration array in L/s/s, where L is length (e.g., meters)
31
+
32
+ Keyword Args:
33
+ target: desired ratio of polynomial fit amplitude to displacement amplitude (default=0.02)
34
+ tol: tolerance for fchp (default=0.001)
35
+ poly_order: order of polynomial to fit to filtered displacement record (default=6)
36
+ maxiter: maximum number of iterations (default=30)
37
+ fchp_min: minimum frequency in Hz to consider for fchp (default=0.001)
38
+ fchp_max: maximum frequency in Hz to consider for fchp (default=0.5)
39
+ tukey_alpha: alpha parameter for scipy.signal.windows.tukey (default=0.05)
40
+ apply_disp_ratio: flag to indicate whether to apply objective 2 (default=0)
41
+ disp_ratio_time: duration in seconds of the initial portion of the record before the p-wave arrival (default=30)
42
+ disp_ratio_target: target ratio of amplitude of initial portion of displacement record to amplitude of displacement record
43
+ """
44
+ get_residual1(fchp, *args):
45
+ """Return the residual defined as disp_fit/disp_filt - target.
46
+
47
+ Args:
48
+ fchp = High-pass corner frequency
49
+ Fdisp = Numpy array containing Fourier coefficients of displacement record
50
+ time = Numpy array containing time values
51
+ poly_order = Order of polynomial to fit to filtered displacement
52
+ target = Desired ratio of polynomial fit amplitude to displacement signal amplitude
53
+ freq = Numpy array containing frequency values
54
+
55
+ Computed variables:
56
+ filt = Coefficients of 5th order Butterworth filter
57
+ Fdisp_filt = Numpy array containing Fourier coefficients of filtered displacement record
58
+ disp_filt = Numpy array containing filtered displacement record
59
+ coef = Coefficients of polynomial fit to displacement record
60
+ disp_fit = Numpy array containing polynomial fit ordinates at each time
61
+ """
62
+
63
+
64
+ get_residual2(fchp, *args):
65
+ """Return the residual defined as disp_init/disp - target.
66
+
67
+ Args:
68
+ fchp = High-pass corner frequency
69
+ Fdisp = Numpy array containing Fourier coefficients of displacement record
70
+ time = Numpy array containing time values
71
+ disp_time = Duration of initial portion of record before p-wave arrival
72
+ disp_target = Desired ratio of amplitude of initial portion of displacement record to amplitude of displacement record
73
+ freq = Numpy array containing frequency values
74
+
75
+ Computed variables:
76
+ filt = Coefficients of 5th order Butterworth filter
77
+ Fdisp_filt = Numpy array containing Fourier coefficients of filtered displacement record
78
+ disp_filt = Numpy array containing filtered displacement record
79
+ """
80
+ ```
@@ -0,0 +1,23 @@
1
+ [tool.poetry]
2
+ name = "ucla_geotech_tools"
3
+ version = "1.0.0"
4
+ description = "A collection of software tools developed by the UCLA geotechnical group"
5
+ authors = ["Scott J. Brandenberg"]
6
+ license = "LICENSE.txt"
7
+ readme = "README.md"
8
+
9
+ packages = [
10
+ {include = "ucla_geotech_tools", from = "src"},
11
+ ]
12
+
13
+ [tool.poetry.dependencies]
14
+ python = "^3.8"
15
+ numpy = "^1.22"
16
+ scipy = "^1.8"
17
+
18
+ [tool.poetry.group.test.dependencies]
19
+ obspy = "^1.4.0"
20
+
21
+ [build-system]
22
+ requires = ["poetry-core"]
23
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,193 @@
1
+ import scipy as sp
2
+ import numpy as np
3
+
4
+
5
+ def get_residual1(fchp, *args):
6
+ """Return the residual defined as disp_fit/disp_filt - target.
7
+
8
+ Args:
9
+ fchp = High-pass corner frequency
10
+ Fdisp = Numpy array containing Fourier coefficients of displacement record
11
+ time = Numpy array containing time values
12
+ poly_order = Order of polynomial to fit to filtered displacement
13
+ target = Desired ratio of polynomial fit amplitude to displacement signal amplitude
14
+ freq = Numpy array containing frequency values
15
+
16
+ Computed variables:
17
+ filt = Coefficients of 5th order Butterworth filter
18
+ Fdisp_filt = Numpy array containing Fourier coefficients of filtered displacement record
19
+ disp_filt = Numpy array containing filtered displacement record
20
+ coef = Coefficients of polynomial fit to displacement record
21
+ disp_fit = Numpy array containing polynomial fit ordinates at each time
22
+ """
23
+ Fdisp = args[0]
24
+ time = args[1]
25
+ poly_order = args[2]
26
+ target = args[3]
27
+ freq = args[4]
28
+ filter_order = args[5]
29
+ filt = np.zeros(len(Fdisp))
30
+ filt[freq > 0] = 1 / np.sqrt(1 + (fchp / freq[freq > 0]) ** (2 * filter_order))
31
+ Fdisp_filt = Fdisp * filt
32
+ disp_filt = np.fft.irfft(Fdisp_filt)
33
+ coef = np.polyfit(time[0 : len(disp_filt)], disp_filt, poly_order)
34
+ disp_fit = np.polyval(coef, time)
35
+ return np.max(np.abs(disp_fit)) / np.max(np.abs(disp_filt)) - target
36
+
37
+
38
+ def get_residual2(fchp, *args):
39
+ """Return the residual defined as disp_init/disp - target.
40
+
41
+ Args:
42
+ fchp = High-pass corner frequency
43
+ Fdisp = Numpy array containing Fourier coefficients of displacement record
44
+ time = Numpy array containing time values
45
+ disp_time = Duration of initial portion of record before p-wave arrival
46
+ disp_target = Desired ratio of amplitude of initial portion of displacement record to amplitude of displacement record
47
+ freq = Numpy array containing frequency values
48
+
49
+ Computed variables:
50
+ filt = Coefficients of 5th order Butterworth filter
51
+ Fdisp_filt = Numpy array containing Fourier coefficients of filtered displacement record
52
+ disp_filt = Numpy array containing filtered displacement record
53
+ """
54
+ Fdisp = args[0]
55
+ time = args[1]
56
+ disp_time = args[2]
57
+ disp_target = args[3]
58
+ freq = args[4]
59
+ filter_order = args[5]
60
+ filt = np.zeros(len(Fdisp))
61
+ filt[freq > 0] = 1 / np.sqrt(1 + (fchp / freq[freq > 0]) ** (2 * filter_order))
62
+ Fdisp_filt = Fdisp * filt
63
+ disp_filt = np.fft.irfft(Fdisp_filt)
64
+ return (
65
+ np.max(np.abs(disp_filt[time <= disp_time])) / np.max(np.abs(disp_filt))
66
+ - disp_target
67
+ )
68
+
69
+
70
+ def get_fchp(dt, acc, **kwargs):
71
+ """Return the high-pass corner frequency value that stabilizes the displacement of a ground motion record.
72
+
73
+ The high-pass corner frequency, fchp, is selected to satisfy two objectives:
74
+ 1. A polynomial is fit to the filtered displacement record, and the amplitude of the polynomial fit
75
+ divided by the amplitude of the filtered displacement record is within a tolerance of a specified target.
76
+ 2. The amplitude of the initial portion of the displacement record before the p-wave arrival divided by
77
+ the amplitude of the filtered displacement record is within a tolerance of a specified target.
78
+
79
+ The value of fchp is computed numerically using the Scipy package optimize.ridder(). Two initial values
80
+ of fchp are provided that bracket the root, and the Scipy package solves for the root that minimizes the
81
+ objective function. The tolerance is on the value of fchp (i.e., xtol in optimize.ridder)
82
+
83
+ A value of fchp is obtained first to satisfy objective 1. Objective 2 is optional, and if it is applied,
84
+ the value of fchp from objective 1 is checked against objective 2. If the residual from objective 2 is
85
+ less than or equal to zero, fchp is set equal to the value from objective 1. Otherwise, iterations are
86
+ performed to satisfy objective 2.
87
+
88
+ Args:
89
+ dt (float): time step in seconds
90
+ acc (numpy array, dtype=float): acceleration array in L/s/s
91
+
92
+ Keyword Args:
93
+ target: desired ratio of polynomial fit amplitude to displacement amplitude (default=0.02)
94
+ tol: tolerance for fchp (default=0.001)
95
+ poly_order: order of polynomial to fit to filtered displacement record (default=6)
96
+ maxiter: maximum number of iterations (default=30)
97
+ fchp_min: minimum frequency in Hz to consider for fchp (default=0.001)
98
+ fchp_max: maximum frequency in Hz to consider for fchp (default=0.5)
99
+ tukey_alpha: alpha parameter for scipy.signal.windows.tukey (default=0.05)
100
+ apply_disp_ratio: flag to indicate whether to apply objective 2 (default=0)
101
+ disp_ratio_time: duration in seconds of the initial portion of the record before the p-wave arrival (default=30)
102
+ disp_ratio_target: target ratio of amplitude of initial portion of displacement record to amplitude of displacement record
103
+ """
104
+ options = [
105
+ "dt",
106
+ "acc",
107
+ "target",
108
+ "tol",
109
+ "poly_order",
110
+ "maxiter",
111
+ "fchp_min",
112
+ "fchp_max",
113
+ "filter_order",
114
+ "tukey_alpha",
115
+ "filter_type",
116
+ "disp_ratio",
117
+ "disp_ratio_time",
118
+ "disp_ratio_target",
119
+ ]
120
+
121
+ for key, value in kwargs.items():
122
+ if key not in options:
123
+ print(
124
+ key
125
+ + " is not a valid argument. Please see documentation. Using default values for all parameters that are not specified."
126
+ )
127
+ exit(1)
128
+
129
+ target = kwargs.get("target", 0.02)
130
+ tol = kwargs.get("tol", 0.001)
131
+ poly_order = kwargs.get("poly_order", 6)
132
+ maxiter = kwargs.get("maxiter", 30)
133
+ fchp_min = kwargs.get("fchp_min", 0.001)
134
+ fchp_max = kwargs.get("fchp_max", 0.5)
135
+ filter_order = kwargs.get("filter_order", 5.0)
136
+ tukey_alpha = kwargs.get("tukey_alpha", 0.05)
137
+ apply_disp_ratio = kwargs.get("apply_disp_ratio", 0)
138
+ disp_ratio_time = kwargs.get("disp_ratio_time", 30)
139
+ disp_ratio_target = kwargs.get("disp_ratio_target", 0.02)
140
+
141
+ # Signal pre-processing. Subtract weighted mean, apply tukey window, define time, take FFT, compute Fdisp
142
+ if len(acc) % 2 != 0:
143
+ acc = acc[0:-1]
144
+ window = sp.signal.windows.tukey(len(acc), alpha=tukey_alpha)
145
+ meanacc = np.average(acc, weights=window)
146
+ acc = window * (acc - meanacc)
147
+ time = np.linspace(0, dt * len(acc), len(acc))
148
+ Facc = np.fft.rfft(acc)
149
+ freq = np.fft.rfftfreq(len(acc), dt)
150
+ Fdisp = np.zeros(len(Facc), dtype="complex")
151
+ Fdisp[freq > 0] = Facc[freq > 0] / -((2 * np.pi * freq[freq > 0]) ** 2)
152
+
153
+ # Solve fchp for objective 1
154
+ R0 = get_residual1(fchp_min, Fdisp, time, poly_order, target, freq, filter_order)
155
+ R2 = get_residual1(fchp_max, Fdisp, time, poly_order, target, freq, filter_order)
156
+ if np.sign(R0) != np.sign(R2):
157
+ fchp = sp.optimize.ridder(
158
+ get_residual1,
159
+ fchp_min,
160
+ fchp_max,
161
+ args=(Fdisp, time, poly_order, target, freq, filter_order),
162
+ xtol=tol,
163
+ maxiter=maxiter,
164
+ )
165
+ elif np.sign(R0) < 0:
166
+ fchp = minfc
167
+ elif np.sign(R2) > 0:
168
+ fchp = fchp_max
169
+
170
+ # Solve fchp for objective 2 if apply_disp_ratio is not zero
171
+ if apply_disp_ratio == 0:
172
+ return fchp
173
+ R0 = get_residual2(
174
+ fchp, Fdisp, time, disp_ratio_time, disp_ratio_target, freq, filter_order
175
+ )
176
+ R2 = get_residual2(
177
+ fchp_max, Fdisp, time, disp_ratio_time, disp_ratio_target, freq, filter_order
178
+ )
179
+ if np.sign(R0) != np.sign(R2):
180
+ fchp = sp.optimize.ridder(
181
+ get_residual2,
182
+ fchp,
183
+ fchp_max,
184
+ args=(Fdisp, time, disp_ratio_time, disp_ratio_target, freq, filter_order),
185
+ xtol=tol,
186
+ maxiter=maxiter,
187
+ )
188
+ elif np.sign(R0) < 0:
189
+ fchp = fchp
190
+ elif np.sign(R2) > 0:
191
+ fchp = fchp_max
192
+
193
+ return fchp
@@ -0,0 +1,55 @@
1
+ import numpy as np
2
+
3
+ def get_ngawest2_T():
4
+ return(np.asarray([0.01, 0.02, 0.022, 0.025, 0.029, 0.030, 0.032, 0.035, 0.036, 0.040, 0.042, 0.044, 0.045, 0.046, 0.048, 0.050, 0.055, 0.060, 0.065, 0.067, 0.070, 0.075, 0.080, 0.085, 0.090, 0.095, 0.100, 0.11, 0.12, 0.13, 0.133, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.22, 0.24, 0.25, 0.26, 0.28, 0.29, 0.30, 0.32, 0.34, 0.35, 0.36, 0.38, 0.40, 0.42, 0.44, 0.45, 0.46, 0.48, 0.50, 0.55, 0.60, 0.65, 0.667, 0.70, 0.75, 0.80, 0.85, 0.90, 0.95, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0, 2.2, 2.4, 2.5, 2.6, 2.8, 3.0, 3.2, 3.4, 3.5, 3.6, 3.8, 4.0, 4.2, 4.4, 4.6, 4.8, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 20.0]))
5
+
6
+ def next_fast_len(target):
7
+ I2 = 0
8
+ while(2.0**I2<target):
9
+ I2+=1
10
+ I3 = 0
11
+ while(3.0**I3<target):
12
+ I3+=1
13
+ I5 = 0
14
+ while(5.0**I5<target):
15
+ I5+=1
16
+ return np.min([2.0**I2, 3.0**I3, 5.0**I5])
17
+
18
+ def get_ARS(T,D,motions,dt,zeropad):
19
+ if(zeropad==1):
20
+ NFFT = next_fast_len(len(motions))
21
+ else:
22
+ NFFT = len(motions[0])
23
+ freq = np.fft.rfftfreq(NFFT,dt)
24
+ Fmotions = np.fft.rfft(motions)
25
+ Sa = [None]*len(motions)
26
+ for i, Fmotion in enumerate(Fmotions):
27
+ Fconvolved_motion = Fmotion/(1.0+2.0j*D*freq*T[:,np.newaxis]-freq**2*T[:,np.newaxis]**2)
28
+ convolved_motion = np.fft.irfft(Fconvolved_motion)
29
+ Sa[i] = np.max(np.absolute(convolved_motion),axis=1)
30
+ return np.asarray(Sa)
31
+
32
+
33
+ def get_response_spectrum(**kwargs):
34
+ if('motions' not in kwargs):
35
+ print('you must specify motions')
36
+ exit(1)
37
+ if('dt' not in kwargs):
38
+ print('you must specify dt')
39
+ exit(1)
40
+ verbose = kwargs.get('verbose',1)
41
+ T = kwargs.get('T',get_ngawest2_T())
42
+ motions = kwargs['motions']
43
+ D = kwargs.get('D',0.05)
44
+ zeropad = kwargs.get('zeropad',1)
45
+ dt = kwargs['dt']
46
+ if('RotD' in kwargs):
47
+ if((motions.shape[0]!=2)):
48
+ print('You must specify two motions instead of '+ str(motions.shape[0]) + ' if you specify RotD')
49
+ exit(1)
50
+ RotD = np.asarray(kwargs['RotD'],dtype='float64')
51
+ if(len(RotD)==1):
52
+ RotD = RotD.reshape((RotD.size, 1))
53
+ return get_rotD_ARS(T,D,motions[0],motions[1],dt,zeropad,RotD,100)
54
+ else:
55
+ return get_ARS(T,D,motions,dt,zeropad)