1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module for the handling of Frame Order."""
24
25
26 from math import cos, pi, sin
27 from numpy import divide, dot, eye, float64, multiply, sinc, swapaxes, tensordot
28 try:
29 from scipy.integrate import quad
30 except ImportError:
31 pass
32
33
34 from lib.compat import norm
35 from lib.frame_order.matrix_ops import rotate_daeg
36
37
39 """Generate the 1st degree Frame Order matrix for the rotor model.
40
41 @param matrix: The Frame Order matrix, 1st degree to be populated.
42 @type matrix: numpy 3D, rank-2 array
43 @param R_eigen: The eigenframe rotation matrix.
44 @type R_eigen: numpy 3D, rank-2 array
45 @param sigma_max: The maximum torsion angle.
46 @type sigma_max: float
47 """
48
49
50 matrix[:] = 0.0
51
52
53 val = sinc(sigma_max/pi)
54
55
56 matrix[0, 0] = val
57 matrix[1, 1] = val
58 matrix[2, 2] = 1.0
59
60
61 return rotate_daeg(matrix, R_eigen)
62
63
65 """Generate the rotated 2nd degree Frame Order matrix for the rotor model.
66
67 The cone axis is assumed to be parallel to the z-axis in the eigenframe.
68
69
70 @param matrix: The Frame Order matrix, 2nd degree to be populated.
71 @type matrix: numpy 9D, rank-2 array
72 @param Rx2_eigen: The Kronecker product of the eigenframe rotation matrix with itself.
73 @type Rx2_eigen: numpy 9D, rank-2 array
74 @param smax: The maximum torsion angle.
75 @type smax: float
76 """
77
78
79 matrix[:] = 0.0
80
81
82 sinc_smax = sinc(smax/pi)
83 sinc_2smax = sinc(2.0*smax/pi)
84
85
86 matrix[0, 0] = (sinc_2smax + 1.0) / 2.0
87 matrix[1, 1] = matrix[0, 0]
88 matrix[2, 2] = sinc_smax
89 matrix[3, 3] = matrix[0, 0]
90 matrix[4, 4] = matrix[0, 0]
91 matrix[5, 5] = matrix[2, 2]
92 matrix[6, 6] = matrix[2, 2]
93 matrix[7, 7] = matrix[2, 2]
94 matrix[8, 8] = 1.0
95
96
97 matrix[0, 4] = matrix[4, 0] = -(sinc_2smax - 1.0) / 2.0
98
99
100 matrix[1, 3] = matrix[3, 1] = -matrix[0, 4]
101
102
103 return rotate_daeg(matrix, Rx2_eigen)
104
105
106 -def pcs_numeric_qr_int_rotor(points=None, max_points=None, sigma_max=None, c=None, full_in_ref_frame=None, r_pivot_atom=None, r_pivot_atom_rev=None, r_ln_pivot=None, A=None, R_eigen=None, RT_eigen=None, Ri_prime=None, pcs_theta=None, pcs_theta_err=None, missing_pcs=None):
107 """Determine the averaged PCS value via numerical integration.
108
109 @keyword points: The Sobol points in the torsion-tilt angle space.
110 @type points: numpy rank-2, 3D array
111 @keyword max_points: The maximum number of Sobol' points to use. Once this number is reached, the loop over the Sobol' torsion-tilt angles is terminated.
112 @type max_points: int
113 @keyword sigma_max: The maximum rotor angle.
114 @type sigma_max: float
115 @keyword c: The PCS constant (without the interatomic distance and in Angstrom units).
116 @type c: numpy rank-1 array
117 @keyword full_in_ref_frame: An array of flags specifying if the tensor in the reference frame is the full or reduced tensor.
118 @type full_in_ref_frame: numpy rank-1 array
119 @keyword r_pivot_atom: The pivot point to atom vector.
120 @type r_pivot_atom: numpy rank-2, 3D array
121 @keyword r_pivot_atom_rev: The reversed pivot point to atom vector.
122 @type r_pivot_atom_rev: numpy rank-2, 3D array
123 @keyword r_ln_pivot: The lanthanide position to pivot point vector.
124 @type r_ln_pivot: numpy rank-2, 3D array
125 @keyword A: The full alignment tensor of the non-moving domain.
126 @type A: numpy rank-2, 3D array
127 @keyword R_eigen: The eigenframe rotation matrix.
128 @type R_eigen: numpy rank-2, 3D array
129 @keyword RT_eigen: The transpose of the eigenframe rotation matrix (for faster calculations).
130 @type RT_eigen: numpy rank-2, 3D array
131 @keyword Ri_prime: The array of pre-calculated rotation matrices for the in-frame rotor motion, used to calculate the PCS for each state i in the numerical integration.
132 @type Ri_prime: numpy rank-3, array of 3D arrays
133 @keyword pcs_theta: The storage structure for the back-calculated PCS values.
134 @type pcs_theta: numpy rank-2 array
135 @keyword pcs_theta_err: The storage structure for the back-calculated PCS errors.
136 @type pcs_theta_err: numpy rank-2 array
137 @keyword missing_pcs: A structure used to indicate which PCS values are missing.
138 @type missing_pcs: numpy rank-2 array
139 """
140
141
142 pcs_theta[:] = 0.0
143 pcs_theta_err[:] = 0.0
144
145
146 Ri = dot(R_eigen, tensordot(Ri_prime, RT_eigen, axes=1))
147 Ri = swapaxes(Ri, 0, 1)
148
149
150 sigma = points[0]
151
152
153 num = 0
154 for i in range(len(points[0])):
155
156 if num == max_points:
157 break
158
159
160 if abs(sigma[i]) > sigma_max:
161 continue
162
163
164 pcs_pivot_motion_rotor_qr_int(full_in_ref_frame=full_in_ref_frame, r_pivot_atom=r_pivot_atom, r_pivot_atom_rev=r_pivot_atom_rev, r_ln_pivot=r_ln_pivot, A=A, Ri=Ri[i], pcs_theta=pcs_theta, pcs_theta_err=pcs_theta_err, missing_pcs=missing_pcs)
165
166
167 num += 1
168
169
170 if num == 0:
171
172 Ri_prime = eye(3, dtype=float64)
173 Ri = dot(R_eigen, tensordot(Ri_prime, RT_eigen, axes=1))
174 Ri = swapaxes(Ri, 0, 1)
175
176
177 pcs_pivot_motion_rotor_qr_int(full_in_ref_frame=full_in_ref_frame, r_pivot_atom=r_pivot_atom, r_pivot_atom_rev=r_pivot_atom_rev, r_ln_pivot=r_ln_pivot, A=A, Ri=Ri, pcs_theta=pcs_theta, pcs_theta_err=pcs_theta_err, missing_pcs=missing_pcs)
178
179
180 multiply(c, pcs_theta, pcs_theta)
181
182
183 else:
184 multiply(c, pcs_theta, pcs_theta)
185 divide(pcs_theta, float(num), pcs_theta)
186
187
188 -def pcs_numeric_quad_int_rotor(sigma_max=None, c=None, r_pivot_atom=None, r_ln_pivot=None, A=None, R_eigen=None, RT_eigen=None, Ri_prime=None):
189 """Determine the averaged PCS value via SciPy quadratic numerical integration.
190
191 @keyword sigma_max: The maximum rotor angle.
192 @type sigma_max: float
193 @keyword c: The PCS constant (without the interatomic distance and in Angstrom units).
194 @type c: float
195 @keyword r_pivot_atom: The pivot point to atom vector.
196 @type r_pivot_atom: numpy rank-1, 3D array
197 @keyword r_ln_pivot: The lanthanide position to pivot point vector.
198 @type r_ln_pivot: numpy rank-1, 3D array
199 @keyword A: The full alignment tensor of the non-moving domain.
200 @type A: numpy rank-2, 3D array
201 @keyword R_eigen: The eigenframe rotation matrix.
202 @type R_eigen: numpy rank-2, 3D array
203 @keyword RT_eigen: The transpose of the eigenframe rotation matrix (for faster calculations).
204 @type RT_eigen: numpy rank-2, 3D array
205 @keyword Ri_prime: The empty rotation matrix for the in-frame rotor motion, used to calculate the PCS for each state i in the numerical integration.
206 @type Ri_prime: numpy rank-2, 3D array
207 @return: The averaged PCS value.
208 @rtype: float
209 """
210
211
212 Ri_prime[0, 2] = 0.0
213 Ri_prime[1, 2] = 0.0
214 Ri_prime[2, 0] = 0.0
215 Ri_prime[2, 1] = 0.0
216 Ri_prime[2, 2] = 1.0
217
218
219 result = quad(pcs_pivot_motion_rotor_quad_int, -sigma_max, sigma_max, args=(r_pivot_atom, r_ln_pivot, A, R_eigen, RT_eigen, Ri_prime))
220
221
222 SA = 2.0 * sigma_max
223
224
225 return c * result[0] / SA
226
227
228 -def pcs_pivot_motion_rotor_qr_int(full_in_ref_frame=None, r_pivot_atom=None, r_pivot_atom_rev=None, r_ln_pivot=None, A=None, Ri=None, pcs_theta=None, pcs_theta_err=None, missing_pcs=None):
229 """Calculate the PCS value after a pivoted motion for the rotor model.
230
231 @keyword full_in_ref_frame: An array of flags specifying if the tensor in the reference frame is the full or reduced tensor.
232 @type full_in_ref_frame: numpy rank-1 array
233 @keyword r_pivot_atom: The pivot point to atom vector.
234 @type r_pivot_atom: numpy rank-2, 3D array
235 @keyword r_pivot_atom_rev: The reversed pivot point to atom vector.
236 @type r_pivot_atom_rev: numpy rank-2, 3D array
237 @keyword r_ln_pivot: The lanthanide position to pivot point vector.
238 @type r_ln_pivot: numpy rank-2, 3D array
239 @keyword A: The full alignment tensor of the non-moving domain.
240 @type A: numpy rank-2, 3D array
241 @keyword Ri: The frame-shifted, pre-calculated rotation matrix for state i.
242 @type Ri: numpy rank-2, 3D array
243 @keyword pcs_theta: The storage structure for the back-calculated PCS values.
244 @type pcs_theta: numpy rank-2 array
245 @keyword pcs_theta_err: The storage structure for the back-calculated PCS errors.
246 @type pcs_theta_err: numpy rank-2 array
247 @keyword missing_pcs: A structure used to indicate which PCS values are missing.
248 @type missing_pcs: numpy rank-2 array
249 """
250
251
252 rot_vect = dot(r_pivot_atom, Ri) + r_ln_pivot
253
254
255 length = 1.0 / norm(rot_vect, axis=1)**5
256
257
258 if min(full_in_ref_frame) == 0:
259 rot_vect_rev = dot(r_pivot_atom_rev, Ri) + r_ln_pivot
260 length_rev = 1.0 / norm(rot_vect_rev, axis=1)**5
261
262
263 for j in range(len(r_pivot_atom[:, 0])):
264
265 for i in range(len(pcs_theta)):
266
267 if missing_pcs[i, j]:
268 continue
269
270
271 if full_in_ref_frame[i]:
272 proj = dot(rot_vect[j], dot(A[i], rot_vect[j]))
273 length_i = length[j]
274 else:
275 proj = dot(rot_vect_rev[j], dot(A[i], rot_vect_rev[j]))
276 length_i = length_rev[j]
277
278
279 pcs_theta[i, j] += proj * length_i
280
281
283 """Calculate the PCS value after a pivoted motion for the rotor model.
284
285 @param sigma_i: The rotor angle for state i.
286 @type sigma_i: float
287 @param r_pivot_atom: The pivot point to atom vector.
288 @type r_pivot_atom: numpy rank-1, 3D array
289 @param r_ln_pivot: The lanthanide position to pivot point vector.
290 @type r_ln_pivot: numpy rank-1, 3D array
291 @param A: The full alignment tensor of the non-moving domain.
292 @type A: numpy rank-2, 3D array
293 @param R_eigen: The eigenframe rotation matrix.
294 @type R_eigen: numpy rank-2, 3D array
295 @param RT_eigen: The transpose of the eigenframe rotation matrix (for faster calculations).
296 @type RT_eigen: numpy rank-2, 3D array
297 @param Ri_prime: The empty rotation matrix for the in-frame rotor motion for state i.
298 @type Ri_prime: numpy rank-2, 3D array
299 @return: The PCS value for the changed position.
300 @rtype: float
301 """
302
303
304 c_sigma = cos(sigma_i)
305 s_sigma = sin(sigma_i)
306 Ri_prime[0, 0] = c_sigma
307 Ri_prime[0, 1] = -s_sigma
308 Ri_prime[1, 0] = s_sigma
309 Ri_prime[1, 1] = c_sigma
310
311
312 R_i = dot(R_eigen, dot(Ri_prime, RT_eigen))
313
314
315 vect = dot(R_i, r_pivot_atom) + r_ln_pivot
316
317
318 length = norm(vect)
319
320
321 proj = dot(vect, dot(A, vect))
322
323
324 pcs = proj / length**5
325
326
327 return pcs
328